app-generator / docs

App Generator - The Official Documentation | AppSeed
https://docs.appseed.us
1 stars 1 forks source link

[React] useState #104

Open mahfujul-helios opened 1 month ago

mahfujul-helios commented 1 month ago

useState

what is useState?

The useState hook in React enables easy state management in functional components. It provides a state variable and corresponding setter function, allowing for dynamic updates to the state. React automatically re-renders the component when the state changes. With useState, you can have multiple state variables and update the state based on its previous value, simplifying state management in React applications.

How it works?

The useState hook in React is a powerful feature that enables state management within functional components. It works by providing a state variable and a corresponding setter function, allowing you to store and update state values. When you call useState(initialValue), the initial value is assigned to the state variable. To update the state, you use the setter function, which triggers a re-render of the component and updates the user interface to reflect the new state value. useState simplifies state management and facilitates the creation of dynamic and interactive React applications.

Some Example of useState

Updating objects and arrays in useState

Never directly modify an object or array stored in useState. Instead, you should create a new updated version of the object or array and call setState with the new version. For example:

// Objects
const [state, setState] = useState({ name: 'John', age: 30 });

const updateName = () => {
  setState({ ...state, name: 'Jane' });
};

const updateAge = () => {
  setState({ ...state, age: state.age + 1 });
};

// Arrays
const [array, setArray] = useState([1, 2, 3, 4, 5]);

const addItem = () => {
  setArray([...array, 6]);
};

const removeItem = () => {
  setArray(array.slice(0, array.length - 1));
};

Declaring state in React

useState is a named export from react. To use it, you can write React.useState or import it by writing useState:

import React, { useState } from 'react';

The state object that can be declared in a class and allows you to declare more than one state variable, as shown below:

import React from 'react';

class Message extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: '',
      list: [],    
    };
  }
  /* ... */
}

However, unlike the state object, the useState Hook allows you to declare only one state variable (of any type) at a time, like this:

import React, { useState } from 'react';

const Message= () => {
   const messageState = useState( '' );
   const listState = useState( [] );
}

So, useState takes the initial value of the state variable as an argument, and you can pass it directly, as shown in the previous example. You can also use a function to lazily initialize the variable. This is useful when the initial state is the result of an expensive computation, as shown below:

const Message= () => {
   const messageState = useState( () => expensiveComputation() );
   /* ... */
}

The initial value will be assigned only on the initial render. If it’s a function, it will be executed only on the initial render. In subsequent renders (due to a change of state in the component or a parent component), the argument of the useState Hook will be ignored, and the current value will be retrieved.

It is important to keep this in mind because, for example, if you want to update the state based on the new properties the component receives, using useState alone won’t work. This is because its argument is used the first time only — not every time the property changes (look here for the right way to do this). This is shown here:

const Message= (props) => {
   const messageState = useState( props.message );
   /* ... */
}

But, useState doesn’t return just a variable, as the previous examples imply. It returns an array, where the first element is the state variable and the second element is a function to update the value of the variable:

const Message= () => {
   const messageState = useState( '' );
   const message = messageState[0]; // Contains ''
   const setMessage = messageState[1]; // It's a function
}

Usually, you’ll use array destructuring to simplify the code shown above like this:

const Message= () => {
   const [message, setMessage]= useState( '' );
}

This way, you can use the state variable in the functional component like any other variable:

const Message = () => {
  const [message, setMessage] = useState( '' );

  return (
    <p>
      <strong>{message}</strong>
    </p>
  );
};

But, why does useState return an array? This is because, compared to an object, an array is more flexible and easy to use. If the method returned an object with a fixed set of properties, you wouldn’t be able to assign custom names easily.

Instead, you’d have to do something like this (assuming the properties of the object are state and setState):

// Without using object destructuring
const messageState = useState( '' );
const message = messageState.state;
const setMessage = messageState

// Using object destructuring
const { state: message, setState: setMessage } = useState( '' );
const { state: list, setState: setList } = useState( [] );

Using React Hooks to update the state

The second element returned by useState is a function that takes a new value to update the state variable. Here’s an example that uses a text box to update the state variable on every change:

const Message = () => {
  const [message, setMessage] = useState( '' );

  return (
    <div>
      <input
         type="text"
         value={message}
         placeholder="Enter a message"
         onChange={e => setMessage(e.target.value)}
       />
      <p>
        <strong>{message}</strong>
      </p>
    </div>
  );
};

Working with multiple state variables or one state object

When working with multiple fields or values as the state of your application, you have the option of organizing the state using multiple state variables:

const [id, setId] = useState(-1);
const [message, setMessage] = useState('');
const [author, setAuthor] = useState('');
Or an object state variable:
const [messageObj, setMessage] = useState({ 
  id: 1, 
  message: '', 
  author: '' 
});

However, you have to be careful when using state objects with a complex structure (nested objects). Consider this example:

const [messageObj, setMessage] = useState({
  input: {
    author: {
      id: -1,
      author: {
        fName:'',
        lName: ''
      }
    },
    message: {
      id: -1,
      text: '',
      date: now()
    }
  }
});

If you have to update a specific field nested deep in the object, you’ll have to copy all the other objects along with the key-value pairs of the object that contains that specific field:

setMessage(prevState => ({
  input: {
    ...prevState.input,
    message: {
      ...prevState.input.message, 
      text: 'My message'
    }
  }
}));

Conclusion

useState is a Hook that allows you to have state variables in functional components. You pass the initial state to this function, and it returns a variable with the current state value (not necessarily the initial state) and another function to update this value.