# State, Events & Lists

## Managing State

We manage state in a react native app in the same way we managed state in a react web app. We use the inbuilt `useState` hook provided by react to manage the internal state of the app.

## &#x20;Handling Events

We handle event in react native in the same way  we use to do in our react apps. The only difference here is, the core component property names are different! For `Button`, the event handler for `onClick` is `onPress`, whereas for `TextInput`, the `onChange` event handler is now `onChangeText`.

## Outputting Lists

We render lists in react native the same way we did in react web apps. Below is a full demonstration of all the above mentioned building blocks for a react native app.

{% code title="App.js" %}

```jsx
import React, {useState} from 'react';
import {StyleSheet, View, Text, TextInput, Button} from 'react-native';
import {StatusBar} from 'expo-status-bar';

const App = () => {
  const [newGoal, setNewGoal] = useState('');
  const [goals, setGoals] = useState([]);
  
  const goalInputHandler = (goal) => {
    setNewGoal(goal)
  }
  
  const addGoalHandler = () => {
    setGoals((prevState) => [...prevState, newGoal])
  }
  
  return (
    <View style={styles.root}>
      <View style={styles.inputContainer}>
        <TextInput
          placeholder="Todo Goals"
          style={styles.input}
          onChangeText={goalInputHandler}
          value={newGoal}
        />
        <Button title="ADD" onPress={addGoalHandler} />
      </View>
      <View>
        {goals.map((goal) => <Text key={Math.random()}>{goal}</Text>)}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  root: { padding: 50},
  inputContainer: {
    flexDirextion: 'row',
    justifyContent: 'space-between',
    alignItems: 'center'
  },
  input: {
    width: '80%',
    padding: 10,
    borderColor: 'black',
    borderWidth: 1
  }
})

export default App;
```

{% endcode %}

## Styling List Items

Since the `Text` component provided by react native does not support much styling options, we will wrap it within a `View` component to provide styling to the list item, which is a `Text` component here.

Also, since we will be repeating the `View` instead of the `Text` component, we will move our `key` prop to the `View` instead of `Text` component.

{% code title="App.js" %}

```jsx
import //...

const App = () => {
  //...
  return (
    <View>
      <View>
        //...
      </View>
      <View>
        {goals.map((goal) => 
          <View key={Math.random()} style={styles.listStyle}>
            <Text>{goal}</Text>
          </View>
        )}
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  //...
  listStyle: {
    padding: 10,
    marginVertical: 10,
    borderColor: 'black',
    backgroundColor: '#cc',
    borderWidth: 1
  }
})

export default App
```

{% endcode %}

This is what it looks like now:

![Lists with state, event handlers and styles.](/files/-Mc_8uf8F3TeYKOYAQNj)

## ScrollView

We need to explicitly tell react native that our app extends beyond the default screen size, and we do so by declaring a `ScrollView` component to the component where we want the content to be scrollable.

In the above example, we would wrap our `View` component with a `ScrollView` component, so that the list of items can be scrollable if there are items that exceed the view of the device.

{% code title="App.js" %}

```jsx
//...
      <ScrollView>
        {goals.map((goal) => 
          <View key={Math.random()} style={styles.listStyle}>
            <Text>{goal}</Text>
          </View>
        )}
      </ScrollView>
```

{% endcode %}

By just adding this component, we can scroll our content that extends beyond the screen size!

## Flatlist: A better list

A `ScrollView` component will be inefficient with very large lists, where we typically do not know the size of the list. `ScrollView` renders all the components in the list, in advance, even the ones that are not visible on the device screen. So scrolling down or performing any operations on such a list with the `ScrollView` component, can significantly slow down our app.

React native offers a component that handles lists with large items, called `FlatList`. We can import this component from `react-native` package as well.

The `FlatList`component has two important properties:

1. **`data`:** This is where we point to our input  data.
2. **`renderItem`:** This accepts a function, which is called for every items in our `data`, to render a list item.
3. **`keyExtractor` :** This is a function that tells the `FlatList` how to extract the key from the `data` prop. By default, the logic is to look at the `item` and look for a `key` or `id` property, but with the `keyExtractor`, we can change this. It accepts a function, that takes in two arguments:
   1. `item`: The item it is looking at.
   2. `index`: The index of the item it is looking at.

{% code title="App.js" %}

```jsx
//...
  const addGoalHandler = () => {
    setCourseGoals((prevState) => [
      ...prevState,
      { key: Math.random().toString(), value: newGoal },
    ]);
  }
  //...
      <FlatList
        data={courseGoals}
        renderItem={(itemData) => (
          <View style={styles.listStyle}>
            <Text>{itemData.item.value}</Text>
          </View>
        )}
      />
```

{% endcode %}

The `FlatList` component automatically adds the `key` property to the list item, but only if the `data` prop in the component follows a certain structure. The `data` we provide to the `FlatList` must be an object with the `key` property. We can then have any other properties within it, so ideally only the `key` property is required for a `FlatList` to automatically add keys to the list items.

{% hint style="info" %}
React Native now supports both `key` and `id` as a property to the `data` props in a `FlatList` component. If we try accessing something like `uid`, it will show us a warning!
{% endhint %}

To use a custom `key` or `id` prop with the `FlatList`, we can make use of the `keyExtractor` prop:

{% code title="App.js" %}

```jsx
//...
  const addGoalHandler = () => {
    setCourseGoals((prevState) => [
      ...prevState,
      { uid: Math.random().toString(), value: newGoal },
    ]);
  }
  //...
      <FlatList
        keyExtractor={(item, index) => item.uid}
        data={courseGoals}
        renderItem={(itemData) => (
          <View style={styles.listStyle}>
            <Text>{itemData.item.value}</Text>
          </View>
        )}
      />
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sydrawat.gitbook.io/react-native/basics/state-and-events.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
