# Manging Component State  and Props

## Props <a href="#id-7964" id="id-7964"></a>

Props are short for *Properties*. The simple rule of thumb is props should not be changed. In the programming world we call it “*Immutable*” or in simple english “Unchangeable”.

> Props are Unchangeable — Immutable

Components receive props from their parent. These props should not be modified inside the component. In React and React Native the data flows in one direction -> From the parent to the child.

You can write your own components that use props. The idea behind props is that you can make a single component that is used in many different places in your app. The parent that is calling the component can set the properties, which could be different in each place.

**Props essentially help you write reusable code.**

```
export default class ScreenOne extends React.Component {
  render () {
    return (
     <View>
     	 <Heading message={'Custom Heading for Screen One'}/>
     </View>
    )
  }
}

// Child component
export default class Heading extends React.Component {
  render () {
    return (
      <View>
        <Text>{this.props.message}</Text>
      </View>
    )
  }
}
Heading.propTypes = {
  message: PropTypes.string
}
Heading.defaultProps = {
  message: 'Heading One'
}
```

This simple example shows how props are used.

In the example above we have a *Heading* component, with a *message* prop. The parent class *ScreenOne* sends the prop to the child component *Heading*.

Notice that the same component *Heading* can be reused several times with different *message* prop values passed to it from different parents components. The key here is to remember that the prop should not be modified inside the *Heading* component.

You can create as many screens as you would like to include the same *Heading* component with different *message* props.

## State <a href="#fbc5" id="fbc5"></a>

State works differently when compared to props. State is internal to a component, while props are passed to a component.

> State can Change — Mutable

In english the *‘state of a being’* refers to the physical condition of a person, and it is a mere state, which changes over time. Well, similarly state in React/React Native is used within components to keep track of information.

Keep in mind not to update state directly using *this.state.* Always use *setState* to update the state objects. Using *setState* re-renders the component and all the child components. This is great, because you don’t have to worry about writing event handlers like other languages.

So when can state be used?

```
class Form extends React.Component {

  constructor (props) {
     super(props)
     this.state = {
       input: ''
     }
  }

handleChangeInput = (text) => {
    this.setState({ input: text })
  }
  
  render () {
    const { input } = this.state

    return (
       <View>
          <TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}}
            onChangeText={this.handleChangeInput}
            value={input}
          />
        </View>
      )
    }
 }
```

Anytime there is data that is going to change within a component, state can be used.

User interaction with components are good examples of how state works. Clicking buttons, checkboxes, filling forms, etc. are examples of user interaction where state can be used within the component.

If you had to fill a form with text inputs, each field in the form will retain it’s state based on the user input. If the user input changes, the state of the text inputs will change, causing a re-rendering of the component and all of it’s child components.

Take a look at the code snippet below to better understand how states works within a form.

In the above code snippet you can see a *Form* class with an *input* state. It renders a text input which accepts the user’s input. Once the user inputs the text, the *onChangeText* is triggered which in turn calls *setState* on *input.*

The *setState* triggers a re-rendering of the component again, and the UI is now updated with the user’s latest input. This simple example illustrates how state within a component can be updated and its usage.

## How to Use App State **-- (from React Native)** <a href="#id-6dab" id="id-6dab"></a>

[`AppState`](https://reactnative.dev/docs/appstate) is a simple API supplied by the [`react-native`](https://www.npmjs.com/package/react-native) framework, so is most likely readily available in your React Native projects now. In it’s most basic usage, we can simply refer to the current App State using its `currentState` property, that will either be `active`, `inactive` or `background`:

```
// get current app state from `AppState`import React, { useState } from 'react'
import { AppState } from 'react-native'const App = (props) => {
  
  const [appState, setAppState] = useState(AppState.currentState);
  ...
}
```

In the above example, the `App` component will store the current state of the app as it is rendered — which will almost certainly be `active`.

This alone is not too useful — the app needs to know when this state changes, which in turn needs to be reflected in the above `useState` hook. To tackle this, event listeners can be attached to `AppState`, that gives the component the opportunity to update with the underlying value:

```
// `AppState` event listeners within `useEffect`const handleAppStateChange = (state: any) => {
  console.log(state);
}useEffect(() => {
  AppState.addEventListener('change', handleAppStateChange);
  return (() => {
    AppState.removeEventListener('change', handleAppStateChange);
  })
}, []);
```

A `useEffect` hook has been introduced here with an empty dependency array, ensuring the event listeners will only mount upon the component’s initial render. `useEffect`’s `return` function is executed when the component unmounts, giving the component an opportunity to remove the event listener.

Let’s make this slightly more intelligent by updating the `AppState` within `handleAppStateChange`, and use another `useEffect` hook to `console.log` that value upon the subsequent re-render:

```
// listening to `AppState` changesconst [appState, setAppState] = useState(AppState.currentState);const handleAppStateChange = (state: any) => {
  setAppState(state);
}useEffect(() => {
  AppState.addEventListener('change', handleAppStateChange);
  return (() => {
    AppState.removeEventListener('change', handleAppStateChange);
  })
}, []);useEffect(() => {
  console.log(appState);
});
```

With this simple setup, we already have the means to handle updates to the App State from within a component. However, there are indeed some limitations to our event listeners in this setup, as they will only ever be aware of the component state at the initial render. We will explore why this is the case further down the article.

But when do these “changes” actually occur? Let’s examine this next in order to understand exactly when these events are firing.

### When AppState changes happen <a href="#b8a1" id="b8a1"></a>

The three values of `AppState` (`active`, `inactive` and `background`) are toggled between two key events:

* Minimising and opening the app, to and from the Home screen. Upon doing so, the app switches between `active` and `background`, with a temporary state of `inactive` as the app is being minimised.
* Entering the app switcher from the app itself. If this is done from within the app, the app state will persistently change to `inactive` until the user leaves app switcher.

To demonstrate this, I have copied the example code from above into the Dashboard screen of an app I personally develop. Notice the changes between App State as I change from foreground to background, and as I enter the app switcher: Demonstrating AppState changes as the app changes from foreground, background and app-switcher

![Image for post](https://miro.medium.com/max/1157/1*a6LO_JY1hzQM8NhKg-7gfA.gif)

What you may have noticed is that we always have a period of `inactive` when minimising the app to the device’s Home screen, before changing again to `background`. In addition, this `inactive` state is only triggered *from within the app*. If you attempt to go into the app switcher while on the device’s Home screen, the app will remain in the `background` state, until it is opened to the foreground again.

### Notice how some apps blur their screens in app switcher? <a href="#id-0a0a" id="id-0a0a"></a>

It is in the temporary `inactive` period that you can make some interesting changes to the app, such as overriding the current screen with a placeholder screen, in the event that the current screen contains confidential information — such as a banking app or FinTech app.

This can be handled simply be rendering a different screen if `AppState.currentState` is `inactive`. If you want this behaviour globally, you could wrap your entire app around a component, say, an `<AppStateManager>` component, that will re-render the app from the top level when the state changes to `inactive`:

```
// render `inactive` screen via top-level `AppStateManager` componentexport const AppStateManager = (props: any) => {  const [appState, setAppState] = useState(AppState.currentState);  const handleAppStateChange = (state: any) => {
    setAppState(state);
  }  useEffect(() => {
    AppState.addEventListener('change', handleAppStateChange);
    return (() => {
      AppState.removeEventListener('change', handleAppStateChange);
    })
  }, []);  return (
    {appState === 'inactive'
     ? <View><Text>Inactive Screen!</Text><View>
     : <>{props.children}</>
     }
  )
}
```

This adds a certain level of security within React Native apps — an arguably compulsory feature for more sensitive applications.

With a high level understanding of `AppState`, let’s now examine how to overcome the limitation of event listeners, that only read component state from the render the event listeners are initialised. This can be solved with Refs.

## Using Refs with Event Listeners to Access True State Values <a href="#id-0060" id="id-0060"></a>

As mentioned above, event listeners will only be aware of the state of the component at the initial render. Because the event listeners are not updated upon subsequent re-renders (when state changes), they will not be aware of those changes taking place.

To see this problem in action, we can increment a counter that will exist in `useState`, and log that counter within an event listener as it is being incremented. As the event listener is not aware of state updates after it is initialised, the counter will always log zero.

The following snippet sets this demo up with an event listener added to [`react-navigation`](https://www.npmjs.com/package/react-navigation)’s `didFocus` event.

*For testing purposes, React Navigation’s `didFocus` and `didBlur` events are really useful for testing component logic, that are triggered as screens are visited and left.*

This event is initialised as the screen in question is visited for the first time — it is the state at this point that will be logged:

```
const [counter, setCounter] = useState(0);// update state every 2 secondssetInterval(() => {
  setCounter(counter + 1);
}, 2000);// console.log `counter` within event listener every 2 secondsuseEffect(() => {
  this.focusListener = props.navigation.addListener('didFocus', async () => {
    setInterval(() => {
      // this will always be 0
      console.log(counter);
    }, 2000);
  });
  
  return (() => {
    this.focusListener.remove();
  })
}, []);
```

Concretely, the event listener will not have access to updated state values. This is an inherent issue to React’s relationship to event listeners in general, and is not just related to `AppState`.

To overcome this, we can use the [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref) hook, as well as [`React.createRef()`](https://reactjs.org/docs/refs-and-the-dom.html), to access real-time state values (from the most recent update), from [`useState`](https://reactjs.org/docs/hooks-reference.html#usestate) *or* from DOM elements.

Firstly visiting `useRef`, we can give event listeners a true state value by making a couple of small changes from the above code:

* Creating a reference to `counter` with `useRef`, and use that inside event listeners instead of using `counter` directly.
* Defining a custom `setCounter` method that will update the ref’s `current` value as well as the `counter` state value. To do this, we can change the name of useState’s `setCounter` to `_setCounter`, and use this inside our custom `setCounter` method.

That may be hard to visualise — here is the updated counter example with `useRef` integrated:

With these changes made, the current state values can now be accessed from within event listeners — event listeners that were initialised on the initial component render.

*This is a necessary workaround when it comes to `AppState`, allowing you to refer to current state values when determining your app state switching logic, where you may need to access local state or updated global state from a Redux store or similar.*

### What about getting current HTML / JSX element state within event listeners? <a href="#da87" id="da87"></a>

In the above example, `useState` values were referenced with `useRef`. But what if we wanted to fetch attributes of rendered elements, such as form elements, or even state from React Native components like[`ScrollView`](https://reactnative.dev/docs/scrollview), where the event listener may need to know the current scroll position. A slightly different approach is needed here.

Let’s take this Scroll View scenario. We can take the following steps to solve this:

* Create a ref to the Scroll View element with `React.createRef`. This will act as a pointer to the element.
* Wrap the above ref with a `useRef` hook, and use *this* reference within event listeners, and within the `ref` prop of `<ScrollView />`.

In this scenario we are wrapping a ref with a `useRef` hook — that may appear confusing, but highlights that the two implementations act differently. Let’s drill down why both APIs are being used.

The first difference is the syntax itself:

```
const scrollview = React.createRef();
const scrollviewRef = React.useRef(scrollview);
```

Now, if we ignored `scrollviewRef` and simply assigned `scrollview` to the `<ScrollView />` `ref` prop, and tried to refer to this value within event listeners, we would get a value of `null`.

Try this yourself with the following snippet:

```
// INCORRECT: attempting to assign `scrollview` as ref and use within event listenerconst scrollview = React.createRef();useEffect(() => {
  this.focusListener = props.navigation.addListener('didFocus', async () => {
    // this will be `null`
    console.log(scrollview.current);
  });
  return (() => {
    this.focusListener.remove();
  })
}, []);
return (
 <ScrollView
    ref={scrollview}
    ...
  />
);
```

The issue here is due to the same reason as the previous `counter` example — at the time the event listeners are being initialised, `scrollview.current` is still `null`, and is yet to be linked to the `<ScrollView />` component.

What we can apply here is the same `useRef` solution, and use *that* reference as the ref prop of `<ScrollView />`:

```
// CORRECT: accessing `ScrollView` ref within event listenerconst scrollview = React.createRef();
const scrollviewRef: any = React.useRef(scrollview);useEffect(() => {
  this.focusListener = props.navigation.addListener('didFocus', async () => {
    // this will now successfully reference <ScrollView />
    console.log(scrollviewRef.current);
  });
  return (() => {
    this.focusListener.remove();
  })
}, []);return (
 <ScrollView
    ref={scrollviewRef}
    ...
  />
);
```

Now our event listeners will successfully reference JSX elements, using `useRefs` ability to persist its reference object for the majority of the component’s lifetime.

*Perhaps a clearer way to think about this solution is that `scrollview` acts as the pointer to `<ScrollView />` on the DOM level, whereas `scrollviewRef` acts as a pointer on the component level.*


---

# 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://tkssharma.gitbook.io/react-training/react-native-core-fundamental/manging-component-state-and-props.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.
