DEV Community

Oluwole Mariam
Oluwole Mariam

Posted on

STATE MANAGEMENT IN REACT

STATE MANAGEMENT IN REACT
WHAT DO YOU UNDERSTAND BY STATE MANAGEMENT?

State is like a box that holds data. For example, you have a box where various books are kept. In this scenerio, the book box holds information that your components needs. Basically, state help a component remember the various books stored in the box. When you want to update the books in the box, there are steps involved and that is basically creating a new book or make a copy of the existing one and then set the state to use the new copy of the state.

const [newTodo, setNewTodo] = useState(0);
Enter fullscreen mode Exit fullscreen mode

The above code snippet means that newTodo holds the current state value and the setNewTodo is the function used to update the state variable data. useState(0)means that data start with a value 0.

State management is all about managing the data which influences the behaviour and rendering of your components. state can change over the lifecyle of a components, and each components of its own state and it could be updated within its component. UseState and setState are used to change a state of a components.

This brings use to explaning what a component is all about because we cant talk about state change without talking about components.

Let's dive right in......

Components
Components are the building blocks of the user interface (UI). They are reusable pieces of code that present parts of the UI. Components can be as simple as a button and as complex as an entire page. Each components can manage its own state and properties which we all know as props.

Props are a way of passing data from a parent to a child components. When a prop is passed down to a child component, it can not be modified but rather read the property and use it.
For example, think of a component as a form and props like a specific details you fill into the form. Or think of a component like a toy car, for the car to move, you need a battery (props).

LOCAL STATE AND GLOBAL STATE
These are important concepts for building dynamic and interactive user interfaces.

LOCAL STATE
Local state simply refers to state that is managed within a single components, this state is temporarily used to manage data or user interface states that does not require you to share with other components.

import React, {useState} from 'react'
function Counter(){
<!-- useState hook initializes the local state  variable count  to 0 -->
const [count , setCount] = useState(0);
return(
<!-- in this return, it returns HTML Syntax -->
<div>
<p>You Clicked {count} times</p>
<button onClick={()=> setCount(count + 1)}> Click me</button>
</div>
);
}
export default Counter;
Enter fullscreen mode Exit fullscreen mode

Explanation of the above code

useState(0): this help us initialize the local state variable count with a value of 0 (the count starts from a default value of 0).

state variable: count holds the current state, and setCount is the function used to update the state.

updating a state: when the button is clicked, setCount(count + 1)updates the count state, which triggers a re-render of the component with the new state value.

GLOBAL STATE

Global state is used when you want to share state across multiple components. This can be used using context API, Redux, or Recoil.

import React, { useState, createContext, useContext } from 'react';
// Create a Context for the global state
const CountContext = createContext();
function CounterProvider({ children }) {
  const [count, setCount] = useState(0);
  return (
    <CountContext.Provider value={{ count, setCount }}>
      {children}
    </CountContext.Provider>
  );
}
function CounterDisplay() {
  const { count } = useContext(CountContext);
  return <p>Global count is {count}</p>;
}
function CounterButton() {
  const { setCount } = useContext(CountContext);
  return (
    <button onClick={() => setCount(prevCount => prevCount + 1)}>
      Increase Global Count
    </button>
  );
}
function App() {
  return (
    <CounterProvider>
      <CounterDisplay />
      <CounterButton />
    </CounterProvider>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Explanation to the above code

createContext() create a context object which holds the global state.

CounterProvider wraps its children in CountContext.Provider, providing the count state and setCount function to all nested components.

CounterDisplay and CounterButton use useContext(CountContext) to access global state. CounterDisplay reads the count, and CounterButton updates the count.

Context API: it is a built-in React API for managing global state without prop drilling.

FUNCTIONAL COMPONENTS
This is a javascript fuctions, it accepts a single object argument and returns a react element
(JSX code to render in the DOM tree). In functional components, we do not have this.state.

function function_name(pass the argument name)
{
pass the function_body
}
Enter fullscreen mode Exit fullscreen mode

For Example

import React, {useState} from 'react'

 const functionalComponent = ()=> {

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

 const increase = () => {

     setCount(count + 1);
     }

     return (

     <div>

     <h1>{count}</h1>

     <button onClick = {increase}>+5</button>

     </div>

     )

     }

 export default functionalComponent
Enter fullscreen mode Exit fullscreen mode

EXPLANATION OF THIS CODE ABOVE
The provided React functional component imports React and the useState hook, defines a component named functionalComponent that uses useState to manage a count state initialized to default state 0, includes an increase function that increments count by 1, returns JSX to display the current count in an h1 element and a button labeled "+5" that calls increase when clicked, and exports the component; however, the button label suggests it should increase by 5, so the increase function should be adjusted accordingly to increment by 5 instead of 1.

CLASS COMPONENTS
It extends React.component and include a render method to return JSX, it also manages a state using this.state and update state using this.setState and leverage on lifecycle method.

LIFECYCLE METHODS IN CLASS COMPONENTS
Lifecycle methods in class components provide hooks into the component's lifecycle, allowing you to run code at specific times during the component's life. This includes mounting, updating, and unmounting phases, as well as error handling. These methods are useful for managing side effects, optimizing performance, and ensuring proper cleanup.

Breakdown of Lifecycle Methods

Mounting Phase

  • constructor(props)
    Initializes the component state.
    Binds methods to the component instance.
    Called once when the component is created.

  • static getDerivedStateFromProps(props, state)
    Syncs the state to the props when the component receives new props.
    Can return an object to update the state, or null if no state update is needed.
    Called during both the mounting and updating phases.

  • componentDidMount()
    Invoked immediately after the component is mounted.
    Used for side effects like fetching data or initializing third-party libraries.
    Called once after the initial render.

Updating Phase

  • shouldComponentUpdate(nextProps, nextState)
    Determines whether the component should re-render in response to state or prop changes.
    Returns true (default) to re-render, or false to prevent re-rendering.
    Useful for performance optimization.

  • getSnapshotBeforeUpdate(prevProps, prevState)
    Captures information from the DOM before it is updated.
    The value returned is passed to componentDidUpdate.
    Used for tasks like saving the scroll position before an update.

  • componentDidUpdate(prevProps, prevState, snapshot)
    Invoked immediately after the component updates.
    Receives previous props, state, and the snapshot from

  • getSnapshotBeforeUpdate.
    Used for performing operations that depend on the DOM being updated.

Unmounting Phase

  • componentWillUnmount() Invoked immediately before the component is unmounted and destroyed. Used for cleanup tasks like cancelling network requests or removing event listeners.

Error Handling

  • static getDerivedStateFromError(error):
    Used to update the state so the next render shows an error boundary.

  • componentDidCatch(error, info)
    Used to log error information and display a fallback UI in case of an error.

Lifecycle of React Components

Example of a code:

import React, { Component } from 'react';

class LifecycleDemo extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    console.log('Constructor: Component is being initialized');
  }

  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps: Sync state to props changes');
    return null; // Return null to indicate no change to state
  }

  componentDidMount() {
    console.log('componentDidMount: Component has been mounted');
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate: Determine if re-render is necessary');
    return true; // Return true to proceed with rendering
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate: Capture current state before update');
    return null; // Return a value to be passed to componentDidUpdate
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('componentDidUpdate: Component was re-rendered');
  }

  componentWillUnmount() {
    console.log('componentWillUnmount: Component is being unmounted');
  }

  increaseCount = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    console.log('Render: Component is rendering');
    return (
      <div>
        <h1>{this.state.count}</h1>
        <button onClick={this.increaseCount}>Increase</button>
      </div>
    );
  }
}

export default LifecycleDemo;
Enter fullscreen mode Exit fullscreen mode

Explanaton to above code
import react, {component} from 'react': react is the main react library while component is the base class for creating react class components.

LifecycleDemo: this is the name of the class component extending component.

constructor(props): initialize the components with props.

super(props): calls the parent class constructor with props.

this.state: set the initial state with count set to 0.

getDerivedStateFromProps: a static method used to update the state based on the props changes.

return null: indicate no changes to the state.

componentDidMount: called after the component is added to the DOM.

shouldComponentUpdate: determines if a re-render is necessary.

nextProps, nextState: new props, new state.

return true: indicate the component should re-render.

getSnapshotBeforeUpdate: this is called right before DOM updates (captures state before DOM updates).

preProps, prevState: the previous props and state.

return null: indicate no snapshop value to be passed.

componentDidUpdate: called after the component updates. I.e executes code after the component updates.

snapshot: value returned from getSnapshotBeforeUpdate.

componentWillUnmount: called right before the component is removed from the DOM. It cleans up before the component unmounts.

this.setState: updates the state with the new count value.

render: it is a required method to returning JSX to define the component's UI.

DIFFERENCE BETWEEN FUNCTIONAL COMPONENTS AND CLASS COMPONENTS
Functional components uses hooks (useState, useeffect) to manage the state and side effects while class component uses the this syntax and lifecycle methods for state and behavior management.

Difference between Class Components and Function Components.

image source:geeks4geeks

Top comments (0)