/  Technology   /  What Is “Lifting State Up” in React?

What Is “Lifting State Up” in React?

 

React Lifting state up is a common pattern that is required for web developers to know. It helps to avoid more complex (and often unnecessary) patterns for control your state.

Let’s Begin with a basic todo app, which be made up of three components: TodoCount, TodoList, and AddTodo.

All of these three components, as their name suggests, are going to need to share some common state.

If you look at TodoCount, this is where you are going to display, up at the top of your apps, how many total to dues you have in your applications.

The TodoList is going to be where you appear all of your todos. It has some starting state with these three items (“item 1”, “item 2”, “item 3”) which you will display within an unordered list.

And finally, you have AddTodo. This consists of a form, where you want to be able to add a new items to this list and right now you are just logging the todo that you type into the input to the console:

// src/App.js
import React from "react";
export default function App() {
  return (
    <>
      <TodoCount />
      <TodoList />
      <AddTodo />
    </>
  );
}
function TodoCount() {
  return <div>Total Todos: </div>;
}
function TodoList() {
  const [todos, setTodos] = React.useState(["item 1", "item 2", "item 3"]);
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo}>{todo}</li>
      ))}
    </ul>
  );
}
function AddTodo() {
  function handleSubmit(event) {
    event.preventDefault();
    const todo = event.target.elements.todo.value;
    console.log(todo);
  }
 return (
    <form onSubmit={handleSubmit}>
      <input type="text" id="todo" />
      <button type="submit">Add Todo</button>
    </form>
  );
}

Here we are creating three functions TodoCount() which is returning “Total Todos” in a paragraph tag. TodoList() which is returning a list of of items [1,2,3,] which is displayed using the map function from javascript. Another function is the AddTodo() function which has nested the handlesubmit () function in it. This AddTodo function undertakes a new todo item with the use of the event.target.value of each item.

Why should you care about lifting state up?

How can you use the concept of react lifting state up to help finish your applications?

These components need to share some state, some todo state and you need to share that todo state order to display the number of todos as well as to update your todo list.

This is where the concept of react lifting state up comes in.

We react lift up state to a common predecessor of components that need it, so that they can all share in the state. This allows us to more simply share state among all of these components that need rely upon it.

What common predecessor should you react lift up your state to so all of these components can read from and update that state? The App components.

Here’s what your app should now look like:

// src/App.js
import React from "react";
export default function App() {
  const [todos, setTodos] = React.useState(["item 1", "item 2", "item 3"]);    
  return (
    <>
      <TodoCount />
      <TodoList />
      <AddTodo />
    </>
  );
}
function TodoCount() {
  return <div>Total Todos: </div>;
}
function TodoList() {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo}>{todo}</li>
      ))}
    </ul>
  );
}
function AddTodo() {
  function handleSubmit(event) {
    event.preventDefault();
    const todo = event.target.elements.todo.value;
    console.log(todo);
  }
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" id="todo" />
      <button type="submit">Add Todo</button>
    </form>
  );
}

On TodoList, let’s add a prop named todos. You can demolition todos from the props object. This is recognize you to see your todo items once again.

Now what about displaying the total number of todos within the TodoCount component.This is another instance in which you can pass down the data as a prop, since TodoCount relies upon that state. Once again, we will provide the same prop, todos, destructure it from the props object and display the total number of todos using

todos.length:

import React from "react";
export default function App() {
  const [todos, setTodos] = React.useState(["item 1", "item 2", "item 3"]);
  return (
    <>
      <TodoCount todos={todos} />
      <TodoList todos={todos} />
      <AddTodo />
    </>
  );
}
function TodoCount({ todos }) {
  return <div>Total Todos: {todos.length}</div>;
}
function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo}>{todo}</li>
      ))}
    </ul>
  );
}

Now the last step, you can add to be able to add a new todo.

This is where your setter function(), and setTodos, comes in. To update your todo state, you do not need to pass down both values, the variable and the setter function , all you need to do is pass down setTodos.

You will pass it down to addTodo as a props(properties) of the same name (setTodos) and destructure it from (properties)props.

As you can see, you’re using your form on submit to get access to the input’s value and whatever was typed into it, which you are putting within a local variable named todo.

Instead of needing to pass down the current todos array list , you can just use an inner function() to get the previous todo’s list  value. This allows you to get last(previous) todos list and  return what you want the new state to be.

This new state will be an array([]), in which you’ll spread all of the  last(previous)  todos and add your new todo as the last element in that array:

import React from "react";
export default function App() {
  const [todos, setTodos] = React.useState(["item 1", "item 2", "item 3"]);
  return (
    <>
      <TodoCount todos={todos} />
      <TodoList todos={todos} />
      <AddTodo setTodos={setTodos} />
    </>
  );
}
function AddTodo({ setTodos }) {
  function handleSubmit(event) {
    event.preventDefault();
    const todo = event.target.elements.todo.value;
    setTodos(prevTodos => [...prevTodos, todo]);
  }
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" id="todo" />
      <button type="submit">Add Todo</button>
    </form>
  );
}

Once you add a new item to your todo list, it is right away added to state. Then you see your TodoList components re-render to display that new item, as well as TodoCount to show the total number of todos which is now 4:

Thus, React Lifting state up is an main pattern for React developers because sometimes we have state that is located within a particular components that also needs to be shared with sibling components.

Instead of using an whole state management library like react Redux and / or React Context, you can just lift the react state up to the closest common predecessor and pass both the state variables and  the state values down as well as any callbacks to update that state.

Output:

 

Leave a comment