DEV Community

Abir Ahmed
Abir Ahmed

Posted on • Updated on

React State ManageMent

Here are all the sections are primarily covered in this blog:

  1. What is state in react?
  2. How you manage state in class component?
  3. How you manage state in functional component?
  4. Example of different types of hook build in hooks.
  5. Context and Customtom hooks
  6. Redux
  7. Which factors will i consider for selection between redux and react context api?

# What is state in react?

In React, state is a built-in object that is used to store data that can change over time within a component. The state object is owned by the component and can be accessed and modified within the component's code. Whenever the state object is changed, the component will automatically re-render to reflect the new state.

State can be used to store information that affects the behavior of the component, such as whether a button is disabled or enabled, whether a dropdown menu is open or closed, or whether a form input is valid or invalid. It can also be used to store data that is retrieved from an API or entered by the user.

# How to manage state in class components?

In object-oriented programming, a constructor is used to create an instance of a class, and the this keyword allows us to access the properties of the current object. The same concept applies to class components in React.

In React, we can initialize the initial state of a component using the constructor method, and manage state using the this.state object. We can update the state using the this.setState method, which is provided by default in React class components.

Whenever setState is called, React automatically re-renders the component with the updated state. Finally, the render method is used to render the component with the current state. This allows us to build dynamic user interfaces that can respond to user input and change over time.

#How to manage state in functional component?

For the functional components, React introduces an entirely new concepts called React Hooks. By using different kinds of hook we able to manage state.

Those which hooks are commonly used for state management include:

_useState:_The useState hook is the most commonly used hook for state management. It allows you to add state to a functional component by declaring a

state variable and a function to update it.

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  const handleButtonClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleButtonClick}>
        Click me
      </button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

useEffect:This hook allows you to perform side effects in your component, such as updating the DOM or fetching data from an API. It can also be used to update state based on changes in props or other state variables.

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

useReducer:This hook allows you to manage state using a reducer function, similar to how state is managed in Redux. It can be useful for managing more complex state, especially if you have multiple related state variables that need to be updated together.

import { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

export default Counter;
Enter fullscreen mode Exit fullscreen mode

useContext:This hook allows you to access data that is stored in a Context object, which can be useful for sharing state between multiple components

import React, { useContext } from 'react';

const MyContext = React.createContext();

function MyComponent() {
  const myValue = useContext(MyContext);
  return <div>{myValue}</div>;
}

function App() {
  return (
    <MyContext.Provider value="Hello World">
      <MyComponent />
    </MyContext.Provider>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

useRef: This hook allows you to create a mutable reference to a DOM node or to a value that persists between renders, which can be useful for managing state that doesn't trigger a re-render

import React, { useRef } from 'react';

function Example() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

While these hooks are often used for state management, they can also be used for other purposes. For example, useEffect can be used for cleanup operations, and useRef can be used to store a reference to a callback function.

#Custom Hooks:

Custom hooks allow you to remove reusable logic from your components. They are created by using the use prefix and can be used just like any other React hook. By using custom hooks, you can keep your code DRY (Don't Repeat Yourself) and make it easier to manage and maintain.

Here's an example of a custom hook that manages the state of a checkbox:

import { useState } from 'react';

function useCheckbox(initialValue = false) {
  const [isChecked, setIsChecked] = useState(initialValue);

  const toggleCheckbox = () => {
    setIsChecked(!isChecked);
  };

  return [isChecked, toggleCheckbox];
}

Enter fullscreen mode Exit fullscreen mode

In this example, the useCheckbox hook returns an array with two values: the current state of the checkbox (a boolean value), and a function to toggle the state. The useState hook is used to initialize the state with an initial value of false.

Custom hooks can also take in arguments, just like regular functions. For example, you could create a custom hook that fetches data from an API:

import { useState, useEffect } from 'react';

function useApi(url) {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (error) {
        console.error(error);
      } finally {
        setIsLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return [data, isLoading];
}

Enter fullscreen mode Exit fullscreen mode

In this example, the useApi hook takes in a URL as an argument, and returns an array with two values: the fetched data (an object or array), and a boolean value indicating whether the data is still loading.
Custom hooks can be used in any component, just like any other React hook. For example, you could use the useCheckbox hook in a form component to manage the state of a checkbox:

import { useState } from 'react';
import useCheckbox from './useCheckbox';

function Form() {
  const [email, setEmail] = useState('');
  const [isChecked, toggleCheckbox] = useCheckbox(false);

  const handleSubmit = (event) => {
    event.preventDefault();
    // Submit the form data
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Email:
        <input type="email" value={email} onChange={(event) => setEmail(event.target.value)} />
      </label>
      <label>
        <input type="checkbox" checked={isChecked} onChange={toggleCheckbox} />
        Subscribe to our newsletter
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

Enter fullscreen mode Exit fullscreen mode

In this example, the Form component uses the useCheckbox hook to manage the state of a checkbox. The isChecked value is passed to the checked prop of the element, and the toggleCheckbox function is passed to the onChange prop.
By using custom hooks, you can make your components more modular and reusable, and reduce the amount of code duplication in your application.

#React Context api

React Context API is a powerful tool for managing state in React applications. It provides a way to share state between components without having to pass it down through multiple levels of the component tree. With Context API, you can create a centralized store for your application's state, which can be accessed and modified by any component that needs it.

The Context API consists of two main parts: the context object and the context provider. The context object is created using the createContext method, which returns an object with two properties: Provider and Consumer. The Provider component is used to wrap the component tree that needs access to the shared state, while the Consumer component is used to access the shared state within a component.

To use the Context API for managing state, you first need to create a context object using the createContext method. For example:

import React, { createContext, useState } from 'react';

export const MyContext = createContext();

function App() {
  const [myState, setMyState] = useState('initial state');

  return (
    <MyContext.Provider value={{ myState, setMyState }}>
      <div>
        <h1>My App</h1>
        <ChildComponent />
      </div>
    </MyContext.Provider>
  );
}

Enter fullscreen mode Exit fullscreen mode

In this example, we have created a context object called MyContext, which contains a state variable called myState and a function to update it called setMyState. We have also wrapped the ChildComponent inside the MyContext.Provider component, which provides the shared state to all the child components.

To access the shared state within a component, you can use the useContext hook. For example:

import React, { useContext } from 'react';
import { MyContext } from './App';

function ChildComponent() {
  const { myState, setMyState } = useContext(MyContext);

  return (
    <div>
      <h2>Child Component</h2>
      <p>My state is: {myState}</p>
      <button onClick={() => setMyState('new state')}>
        Update State
      </button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

In this example, we have imported the MyContext object from the App component and used the useContext hook to access the myState and setMyState variables. We can then use these variables to display and update the shared state within the ChildComponent.

Overall, the React Context API provides a simple and efficient way to manage state in React applications. It allows you to create a centralized store for your application's state, which can be accessed and modified by any component that needs it. By using the useContext hook, you can easily access the shared state within your components and keep your code organized and modular.

#Redux

State management is one of the most important aspects of building a React application. As your application grows in complexity, so does your state. Redux is a state management library that helps to manage your application's state more effectively. In this article, we'll explore how Redux manages state in a React application.

Redux is based on three core principles:

  • Single source of truth: The state of your whole application is stored in an object tree within a single store.

  • State is read-only: The only way to change the state is to emit an action, an object describing what happened.

  • Changes are made with pure functions: To specify how the state tree is transformed by actions, you write pure reducers.

Redux works by managing your application state in a central location called the store. The store holds the state of your application, and every component in your application can access the state from the store. When a component wants to update the state, it must dispatch an action to the store.

An action is a plain JavaScript object that describes what happened. It contains a type property that specifies the type of action being performed and an optional payload that contains any additional data that needs to be passed along with the action.

For example, if you have a todo application, the type of an action could be 'ADD_TODO' and the payload could be an object containing the todo item's text and ID.

Reducers are pure functions that specify how the state of your application should change in response to an action. They take the current state and an action as input and return a new state. Reducers should not modify the existing state but rather return a new state object. The returned state object should be a new object that represents the updated state of the application.

Here's an example of a reducer function that handles the 'ADD_TODO' action:

function todosReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.payload.id,
          text: action.payload.text,
          completed: false
        }
      ];
    default:
      return state;
  }
}

Enter fullscreen mode Exit fullscreen mode

The store is created using the createStore function from the Redux library. It takes a reducer function as an argument and returns a store object. You can then use the store object to access the state and dispatch actions.

In a React application, you can use the connect function from the react-redux library to connect a component to the store. The connect function takes two arguments: mapStateToProps and mapDispatchToProps. mapStateToProps is a function that maps the state from the store to the props of your component, while mapDispatchToProps is a function that maps the dispatch function to the props of your component.

import { connect } from 'react-redux';

function TodoList({ todos, addTodo }) {
  return (
    <div>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
      <button onClick={() => addTodo('New Todo')}>Add Todo</button>
    </div>
  );
}

function mapStateToProps(state) {
  return {
    todos: state.todos
  };
}

function mapDispatchToProps(dispatch) {
  return {
    addTodo: text =>
      dispatch({
        type: 'ADD_TODO',
        payload: {
          id: new Date().getTime(),
          text
        }
      })
  };
}

export default connect(mapStateToProps, mapDispatchToProps

Enter fullscreen mode Exit fullscreen mode

#Which factors will I consider for selection between Redux and React Context API?

When deciding between Redux and React Context API for state management in a React application, there are few factors to consider:

  • Size and complexity of the application: If the application is small and doesn't have complex state management requirements, React Context API might be nice choice. However, for larger applications with complex state management requirements, Redux might be a better choice.

  • Scalability: Redux is designed to be scalable, so it can handle larger applications with ease. React Context API, on the other hand, might become unwieldy if the application grows too large.

  • Performance: React Context API is generally faster than Redux because it doesn't involve the overhead of the Redux store. However, for applications that require frequent updates and large amounts of data, Redux might be faster because it has a more efficient update mechanism.

  • Developer experience: React Context API is simpler to use and requires less boilerplate code than Redux. However, Redux has a well-defined structure and clear separation of concerns, which can make it easier for developers to reason about the application's state.

  • Community and ecosystem: Redux has a large and active community, with a wide range of plugins, middleware, and other tools available. React Context API is newer and has a smaller ecosystem, which might make it more difficult to find the resources and tools needed for a specific use case.

Ultimately, the choice between Redux and React Context API will depend on the specific requirements of the application and the preferences of the development team.

As a beginner level learner of React, I wanted to share my thoughts on state management in React.

React is a popular JavaScript library that is widely used to build user interfaces. State management is an importent aspect of React development because it enables the components to be dynamic and interactive. React provides various built-in ways to manage state, including useState, useEffect, useContext, useReducer, and more.

The useState hook is the simplest way to manage state in a React component. It allows us to define and update state within the component itself. useEffect is another popular hook that enables us to perform side effects like fetching data, subscribing to events, and more.

React Context API is an alternative to the traditional prop drilling approach, where we pass down state and methods through multiple layers of components. Context provides a way to pass data through the component tree without having to pass props down manually at every level.

useReducer hook is another way to manage state in a more structured and scalable way, especially in larger applications. It allows us to define a reducer function and dispatch actions to update the state.

Lastly, the redux is an amazing third-party library for managing state in react app.

In conclusion, choosing the right state management technique in React depends on various factors like application size, complexity, scalability, and developer experience.

I wise different source from internet to complete the blogs. I hope this simple blog helps other beginners like me to understand the basics of React state management.
As this is my first blog, i can make mistakes and there is various place to improve myself. Please feel free to share your feedback and suggestions.

Top comments (4)

Collapse
 
tracygjg profile image
Tracy Gilmore

Hi Abir,
A tip. You might want to include the word javascript immediately inside the code blocks as this will provide syntax highlighting. See
Tracy

Collapse
 
tracygjg profile image
Tracy Gilmore

Hi Abir, Good article but you do have a typo "Customtom" at the top of the post.
Regards, Tracy

Collapse
 
gopalece1986 profile image
gopalece1986

Nice explanation

Collapse
 
mynul436 profile image
Mynul Islam

Awesome, keep going.