Sobes.tech
Junior

How to correctly change the state of components in React?

sobes.tech AI

Answer from AI

State changes in React occur through the setState method for class components or using the useState hook for functional components.

Class components:

// Import React
import React, { Component } from 'react';

// Create a class component
class MyComponent extends Component {
  // Initialize state
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  // Method to change state
  incrementCount = () => {
    // Use setState
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Counter: {this.state.count}</p>
        <button onClick={this.incrementCount}>Increase</button>
      </div>
    );
  }
}

// Export the component
export default MyComponent;
  • setState is asynchronous.
  • setState merges the new state with the current one (shallow merge).
  • setState can accept a function that returns the new state based on the previous state:
// Method to change state using a function
incrementCountFunction = () => {
  this.setState((prevState) => ({
    count: prevState.count + 1
  }));
};

Functional components (using useState):

// Import React and useState
import React, { useState } from 'react';

// Create a functional component
function MyFunctionComponent() {
  // Initialize state with useState
  const [count, setCount] = useState(0); // [current state, function to update]

  // Function to change state
  const incrementCount = () => {
    // Use a function to update state
    setCount(count + 1);
  };

  return (
    <div>
      <p>Counter: {count}</p>
      <button onClick={incrementCount}>Increase</button>
    </div>
  );
}

// Export the component
export default MyFunctionComponent;
  • useState returns an array of two elements: the current state and the function to update it.
  • The update function returned by useState replaces the current state, it does not merge.
  • You can pass a function to the update function if the new state depends on the previous state:
// Function to change state using a function
const incrementCountFunction = () => {
  setCount(prevCount => prevCount + 1);
};

Important points when changing state:

  • Do not modify state directly: Never assign a new value directly to the state property (e.g., this.state.count = 5 or count = 5). React will not detect this change and the component will not re-render.
  • Changing objects and arrays: When changing objects or arrays in state, always create new copies. React compares references to objects/arrays, and if the reference doesn't change, React assumes data hasn't changed and does not trigger a re-render.
// Changing an object in a class component
this.setState(prevState => ({
  user: {
    ...prevState.user, // Copy old properties
    name: 'New Name' // Update the needed property
  }
}));

// Changing an array in a functional component
setItems(prevItems => [...prevItems, 'New Element']); // Add a new element
  • Asynchronous setState: If you need to perform an action after the state has been updated and the component re-rendered, use the second argument of setState (callback function) or the useEffect hook in functional components.
// Callback in setState
this.setState({ count: this.state.count + 1 }, () => {
  console.log('State updated!');
});
// useEffect to react to state change
useEffect(() => {
  console.log('Count state changed:', count);
}, [count]); // Dependency: hook runs when count changes

Comparison of methods:

Characteristic Class component (setState) Functional component (useState)
Syntax Method this.setState(newState[, callback]) Hook const [state, setState] = useState(initialState)
Merging/Replacing Merges new state with current (shallow merge) Replaces current state with new
Asynchronous Asynchronous The update function is asynchronous when called from event handlers, but synchronous when called inside React's render phase
Dependence on previous state Passing a function to setState: this.setState(prevState => ({...})) Passing a function to the update function: setState(prev => ({...}))