DEV Community

Hithesh__k
Hithesh__k

Posted on • Updated on

6 Best practices for react state management in 2023.

There are several best practices to follow when managing state in a React application:

1.Keep the state as minimal as possible: It's important to only store data in the state that is necessary for the component to render. This can help to keep your application's state tree small and easy to manage.

import { useState } from 'react';

function MyComponent() {
  // Only store the data that is necessary for the component to render
  const [state, setState] = useState({
    userName: '',
    userId: ''
  });

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {state.userName}</p>
      <p>User ID: {state.userId}</p>
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

2.Avoid direct manipulation of the state: It's a good practice to avoid directly manipulating the state object. Instead, use React's setState() method to update the state. This ensures that the component will re-render when the state changes, allowing the user interface to stay up-to-date.

import { useState } from 'react';

function MyComponent() {
  const [state, setState] = useState({
    userName: '',
    userId: ''
  });

  const handleNameChange = (event) => {
    // Use setState() to update the state, rather than directly manipulating the state object
    setState({
      ...state,
      userName: event.target.value
    });
  }

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {state.userName}</p>
      <p>User ID: {state.userId}</p>

      {/* Use an event handler to update the state */}
      <input type="text" onChange={handleNameChange} />
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

3.Use a state management library: If your application becomes complex and has a lot of state to manage, it can be helpful to use a state management library like Redux or MobX. These libraries provide a predictable and centralized way to manage state in your application.

import { useReducer } from 'react';
import { createStore } from 'redux';

// Define the reducer function to handle state updates
function reducer(state, action) {
  switch (action.type) {
    case 'SET_USERNAME':
      return {
        ...state,
        userName: action.userName
      };
    case 'SET_USER_ID':
      return {
        ...state,
        userId: action.userId
      };
    default:
      return state;
  }
}

// Create the store with the reducer function
const store = createStore(reducer);

function MyComponent() {
  // Use the store's state as the component's state
  const [state, dispatch] = useReducer(reducer, store.getState());

  const handleNameChange = (event) => {
    // Dispatch an action to update the store's state
    dispatch({
      type: 'SET_USERNAME',
      userName: event.target.value
    });
  }

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {state.userName}</p>
      <p>User ID: {state.userId}</p>

      {/* Use an event handler to update the state */}
      <input type="text" onChange={handleNameChange} />
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

4.Use functional setState(): When updating the state based on the previous state, it's a good idea to use the functional form of setState(), which allows you to pass a function to setState() instead of an object. This function receives the previous state as an argument and returns the new state.

import { useState } from 'react';

function MyComponent() {
  const [state, setState] = useState({
    userName: '',
    userId: ''
  });

  const handleNameChange = (event) => {
    // Use the functional form of setState() to update the state based on the previous state
    setState((prevState) => ({
      ...prevState,
      userName: event.target.value
    }));
  }

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {state.userName}</p>
      <p>User ID: {state.userId}</p>

      {/* Use an event handler to update the state */}
      <input type="text" onChange={handleNameChange} />
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

5.Use the context API: If you have state that needs to be shared across multiple components, consider using the React context API. This allows you to create a "context" that can be shared by any component in the tree, without having to pass props down manually through multiple levels of the component hierarchy.

import { useState } from 'react';

// Create the context with a default value
const UserContext = React.createContext({
  userName: '',
  userId: ''
});

function MyComponent() {
  // Use the context to get the state
  const { userName, userId } = useContext(UserContext);

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {userName}</p>
      <p>User ID: {userId}</p>
    </div>
  )
}

function App() {
  // Use the useState hook to manage the state within the context provider
  const [state, setState] = useState({
    userName: '',
    userId: ''
  });

  const handleNameChange = (event) => {
    setState((prevState) => ({
      ...prevState,
      userName: event.target.value
    }));
  }

  return (
    // Wrap the component tree in the context provider to make the state available to all components
    <UserContext.Provider value={state}>
      <MyComponent />
      <input type="text" onChange={handleNameChange} />
    </UserContext.Provider>
  )
}

Enter fullscreen mode Exit fullscreen mode

6.Use the useReducer hook: If you have complex state logic that involves multiple sub-values or the need to perform calculations based on the previous state, you may want to consider using the useReducer hook. This hook allows you to define a reducer function that handles state updates in a predictable way, similar to how Redux works.

import { useReducer } from 'react';

// Define the reducer function to handle state updates
function reducer(state, action) {
  switch (action.type) {
    case 'SET_USERNAME':
      return {
        ...state,
        userName: action.userName
      };
    case 'SET_USER_ID':
      return {
        ...state,
        userId: action.userId
      };
    default:
      return state;
  }
}

function MyComponent() {
  // Initialize the state with the reducer function
  const [state, dispatch] = useReducer(reducer, {
    userName: '',
    userId: ''
  });

  const handleNameChange = (event) => {
    // Dispatch an action to update the state
    dispatch({
      type: 'SET_USERNAME',
      userName: event.target.value
    });
  }

  return (
    <div>
      {/* Render the state data */}
      <p>Username: {state.userName}</p>
      <p>User ID: {state.userId}</p>

      {/* Use an event handler to update the state */}
      <input type="text" onChange={handleNameChange} />
    </div>
  )
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)