DEV Community

Cover image for useState: Function can have state?
Rajshekhar Yadav
Rajshekhar Yadav

Posted on • Originally published at yadavrajshekhar.hashnode.dev

useState: Function can have state?

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.

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>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

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

import React, {useState} from 'react';
Enter fullscreen mode Exit fullscreen mode

Initialising the state

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

  const count = useState(0);
Enter fullscreen mode Exit fullscreen mode

Reading the state

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

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

Enter fullscreen mode Exit fullscreen mode

For the shake of readability, we prefer array destructuring .

For initialisation,

  const [count, setCount]= useState(0);
Enter fullscreen mode Exit fullscreen mode

For Reading the state,

      <Text style={{fontSize: 30}}>{count[0]}</Text>
Enter fullscreen mode Exit fullscreen mode

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.

<Button
        title="Click Me"
        onPress={() => {
          setCount(8);
        }}
      />
Enter fullscreen mode Exit fullscreen mode

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.

  <Button
        title="Click Me"
        onPress={() => {
          setCount(previousCount => previousCount + 1);
        }}
      />
Enter fullscreen mode Exit fullscreen mode

Using object as state variable

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

 const [userInfo, setUserInfo] = useState({name: 'Raj', age: 27});
Enter fullscreen mode Exit fullscreen mode

For updating the the value we can try this.

  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>
  );
Enter fullscreen mode Exit fullscreen mode

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.

onPress={() => {
          setUserInfo(previous => {
// We can use spread operator
            return {...previous, age: previous.age + 1};
          });
        }}
Enter fullscreen mode Exit fullscreen mode

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.

  const [name, setName] = useState('Raj');
  const [age, setAge] = useState(27);
Enter fullscreen mode Exit fullscreen mode

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.


  const [calculateJson, setCalculateJson] = useState(() => {
    return {
      name: 'Raj',
      age: 27,
    };
  });
Enter fullscreen mode Exit fullscreen mode

Now it will call only first time while rendering.

Rules

  1. Only call Hooks at top level
  2. Only call Hooks from the React-Functions.
  3. If your state depends on previous state try to update using callback.
 onPress={() => {
          setAge(previous => previous + 1);
        }}
Enter fullscreen mode Exit fullscreen mode

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.
  2. useState() returns an array whose first item is current state and second item is a function which is used for updating the state.
  3. useState(initialParam) takes the initial value of the state variable as an argument.
  4. We can update the state by passing a value or using a callback.
  5. Whenever we call useState(), React will re-render the component
  6. 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.
  7. 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.

Stay safe !!

Discussion (0)