useState: Function can have state?
Tags: reactnative, react, javascript, reacthooks
Published: 2022-01-09 10:28:13

## Introduction

There are two types of component in React-native `class component` & `Functional component`.

` useState ` is a hook that allows a functional component to store state variable. If you are working with `class component`, It is equivalent to  `this.state/ this.setState`.  In this article we will try to understand the basic concept of `useState`. 

Alright, let's get started !! 

## The Traditional way  of managing state

In `Class component`,  we have a property `state` for reading the state(hold the state) and `setState` property that can we used  for updating the states. Whenever we update the state it triggers the `render` method.

```javascript
export default class ButtonClick extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  render() {
    return (
      <View>
        <Text>You have clicked this {this.state.count} time(s)</Text>
        <Button
          title="Click"
          onPress={() => this.setState({count: this.state.count + 1})}></Button>
      </View>
    );
  }
}
```
## UseState()

Functional component are just a functions that accept the properties as parameter and returns a valid JSX. Functional component does not have state or any lifecycle method. `useState` provides the facility of managing states in functional component. 

### Anatomy of useState()
 The `useState()` hook sets up an individual state property. It returns an array containing two elements: the current state value, and a function you can call with a new value to update the state.

### Declaring the useState()
Import the useState() package from `react`

```javascript
import React, {useState} from 'react';
``` 

### Initialising the state
The first argument of useState(initialState) is the initial state.

```javascript
  const count = useState(0);
``` 

### Reading the state
As we know useState() returns an array, whose first element is the current state.



```javascript
      <Text style={{fontSize: 30}}>{count[0]}</Text>

``` 

For the shake of readability, we prefer array destructuring .
 

For initialisation, 
```javascript
  const [count, setCount]= useState(0);
``` 
For Reading the state,

```javascript
      <Text style={{fontSize: 30}}>{count[0]}</Text>
``` 

### Updating the State

#### Updating the states with a value 

As we know that useState() return an array whose second item is a function which can we used for updating the state.

```javascript
<Button
        title="Click Me"
        onPress={() => {
          setCount(8);
        }}
      />
``` 

#### Updating the states with a callback

Sometimes there is a scenario, we have to calculate the next state on the basis of previous state, we can update the state with callback.

```javascript
  <Button
        title="Click Me"
        onPress={() => {
          setCount(previousCount => previousCount + 1);
        }}
      />
``` 
### Using object as state variable

We can also initialise and update the object with the useState()

```javascript
 const [userInfo, setUserInfo] = useState({name: 'Raj', age: 27});
``` 
For updating the the value we can try this.

```javascript
  const [userInfo, setUserInfo] = useState({name: 'Raj', age: 27});
  const name = userInfo.name;
  const age = userInfo.age;
  return (
    <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
      <Text style={{fontSize: 12}}>
        My Name is {name}. I am {age} years old
      </Text>
      <Button
        title="Update Info Me"

// It will not merge the object. It will just override the state.
        onPress={() => {
          setUserInfo(previous => {
            return {age: previous.age + 1};
          });
        }}
      />
    </View>
  );
``` 
When we will click on the `Button`, you will notice something interesting. Our `age` will be incremented by one which is correct but  the `name` property is totally disappeared. So this is the problem with the `useState()`, it does not merge the object like we have seen in class component when we call `this.setState`. Actually It is overriding the object with current state.

If we really want to update the object, firstly we have to spread out the previous object and then update it. It will look something like that.

```javascript
onPress={() => {
          setUserInfo(previous => {
// We can use spread operator
            return {...previous, age: previous.age + 1};
          });
        }}
``` 
### Multiple States
When working with multiple fields or values as the state of your application, you have the option of organising the state using multiple state variables. 

```javascript
  const [name, setName] = useState('Raj');
  const [age, setAge] = useState(27);
``` 

### Lazy initialisation of useState
Whenever we executes useState(), React re-renders the component. It is fine if the initial value is primitive value. It will not cause any performance issue.

Suppose, If  we have to perform any expensive calculation (e.g. calculating fibonacci..) , it may cause performance issue. With the help of lazy initialisation we can overcome from this problem.

We can also pass a function  as an argument to useState() for initialising the state.

```javascript

  const [calculateJson, setCalculateJson] = useState(() => {
    return {
      name: 'Raj',
      age: 27,
    };
  });
``` 
Now it will call only first time while rendering.

### Rules
1. Only call Hooks at top level
1. Only call Hooks from the React-Functions.
1. If your state depends on previous state try to update using callback. 

```javascript
 onPress={() => {
          setAge(previous => previous + 1);
        }}
``` 
## Conclusion
This is the basic idea about using useStae(). Let's note down the key point.
1. `useState()` makes functional component more  powerful by allowing them to the process state.
1. `useState()` returns an array whose first item is current state and second item is a function which is used for updating the state.
1. `useState(initialParam)` takes the initial value of the state variable as an argument.
1. We can update the state by passing a value or using a callback.
1. Whenever we call useState(), React will re-render the component
1. If we want to perform expensive calculation while initialising the state, we can do this by passing initial state as a function in `useState(()=>{})`. By doing so render will called only once.
1. `useState()` does not auto merge the objects . We can achieve this with the help of spread operator.



Thanks for reading this article. Feel free to add your suggestions. You can connect with me at [Twitter](https://twitter.com/yrajshekhar231 ). 

Stay safe !!