Article image State: Managing State in React: State Management Patterns

9.6. State: Managing State in React: State Management Patterns

Page 30 | Listen in audio

In the world of React, managing state is one of the most crucial aspects of building dynamic and interactive user interfaces. State in React refers to the data that changes over time and affects what is rendered on the screen. Understanding how to effectively manage state is essential for any developer aiming to build scalable and maintainable React applications. In this section, we will delve into state management patterns, exploring various approaches and tools available for managing state in React applications.

At its core, state management in React involves keeping track of the state of components and ensuring that changes to this state are reflected in the UI. React provides several built-in mechanisms for managing state, such as the useState hook for functional components and the setState method for class components. However, as applications grow in complexity, these basic tools might not suffice, necessitating more sophisticated state management solutions.

Local State Management

Local state refers to state that is managed within a single component. This is often the simplest form of state management and is usually sufficient for small applications or individual components. The useState hook in functional components is the most common way to manage local state. It allows you to declare state variables and update them within the component.

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

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

In class components, local state is managed using the this.state object and the this.setState method.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

Lifting State Up

As your application grows, you might find that multiple components need to share the same state. In such cases, lifting state up is a common pattern. This involves moving the shared state to the closest common ancestor of the components that need it. By doing so, the ancestor component can manage the state and pass it down as props to its children.

Consider a scenario where two sibling components need to display and update the same piece of data. Instead of managing the state in each component, you can lift the state up to their parent component and pass it down as props.

function ParentComponent() {
  const [sharedState, setSharedState] = useState(0);

  return (
    <div>
      <ChildComponentOne sharedState={sharedState} setSharedState={setSharedState} />
      <ChildComponentTwo sharedState={sharedState} />
    </div>
  );
}

function ChildComponentOne({ sharedState, setSharedState }) {
  return (
    <div>
      <p>Shared State: {sharedState}</p>
      <button onClick={() => setSharedState(sharedState + 1)}>Increment</button>
    </div>
  );
}

function ChildComponentTwo({ sharedState }) {
  return <p>Shared State in Child Two: {sharedState}</p>;
}

Context API

While lifting state up works well for small applications, it can become cumbersome as the component tree grows deeper. Passing state through multiple levels of components can lead to "prop drilling," where props are passed down through components that do not need them, just to reach the components that do. The Context API provides a solution to this problem by allowing you to share state across the component tree without having to pass props explicitly.

The Context API involves creating a context object using React.createContext, providing a context value with a Provider, and consuming the context value in components using a Consumer or the useContext hook.

const MyContext = React.createContext();

function App() {
  const [value, setValue] = useState("Hello, World!");

  return (
    <MyContext.Provider value={value}>
      <ChildComponent />
    </MyContext.Provider>
  );
}

function ChildComponent() {
  const value = useContext(MyContext);
  return <p>Context Value: {value}</p>;
}

State Management Libraries

For large and complex applications, even the Context API might not be sufficient. State management libraries like Redux, MobX, and Zustand offer more robust solutions for managing state across large applications.

Redux

Redux is one of the most popular state management libraries in the React ecosystem. It is based on the principles of a single source of truth, state immutability, and predictable state transitions through actions and reducers. Redux provides a centralized store for the entire application's state, allowing any component to access and update state through actions.

import { createStore } from 'redux';

const initialState = { count: 0 };

function reducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
}

const store = createStore(reducer);

store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // { count: 1 }

Redux requires additional setup and boilerplate, but it offers powerful tools for debugging and managing complex state changes, making it a preferred choice for many large applications.

MobX

MobX is another popular state management library that emphasizes simplicity and ease of use. Unlike Redux, MobX uses observable state, allowing components to automatically react to changes in state. This makes MobX more intuitive for developers who prefer a reactive programming model.

import { observable } from 'mobx';

const appState = observable({
  count: 0,
  increment() {
    this.count++;
  }
});

appState.increment();
console.log(appState.count); // 1

MobX's automatic state tracking and reactivity can lead to cleaner and more concise code, but it may introduce complexity in terms of understanding how state changes propagate through the application.

Zustand

Zustand is a relatively newer state management library that aims to provide a simple and minimalistic API for managing state. It is inspired by both Redux and React's Context API, offering a lightweight and flexible solution for state management.

import create from 'zustand';

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 }))
}));

function Counter() {
  const { count, increment } = useStore();
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

Zustand's simplicity and minimalistic approach make it an attractive choice for developers who want a lightweight state management solution without the boilerplate of Redux.

Conclusion

Managing state in React is a fundamental aspect of building robust and interactive applications. From local state management using useState and setState to more advanced patterns like lifting state up, using the Context API, and leveraging state management libraries like Redux, MobX, and Zustand, developers have a wide array of tools and techniques at their disposal.

The choice of state management pattern or library depends on the specific needs and complexity of your application. For small to medium-sized applications, React's built-in state management tools and the Context API might be sufficient. However, for larger applications with complex state interactions, adopting a state management library can provide better scalability and maintainability.

Ultimately, understanding the various state management patterns and choosing the right one for your application will empower you to build efficient, scalable, and maintainable React applications that deliver a seamless user experience.

Now answer the exercise about the content:

What is the primary purpose of state management in React applications?

You are right! Congratulations, now go to the next page

You missed! Try again.

Article image State: Managing State in React: Immutable State Updates

Next page of the Free Ebook:

31State: Managing State in React: Immutable State Updates

7 minutes

Earn your Certificate for this Course for Free! by downloading the Cursa app and reading the ebook there. Available on Google Play or App Store!

Get it on Google Play Get it on App Store

+ 6.5 million
students

Free and Valid
Certificate with QR Code

48 thousand free
exercises

4.8/5 rating in
app stores

Free courses in
video, audio and text