Полное руководство по управлению состоянием React

Полное руководство по управлению состоянием React

11 января 2024 г.

Для разработчиков React понимание того, как эффективно управлять состояниями, является ключом к созданию полнофункциональных приложений. То, как вы обрабатываете данные и выполняете их логику, определяет эффективность ваших приложений.

Поэтому в этом уроке я расскажу вам, как эффективно управлять состояниями с помощью различных методов, таких как useState , крючок useReducer, Context API, набор инструментов Redux и URL-адреса.

Что такое управление состоянием?

Состояние — это текущее значение в приложении в определенный момент времени. Например, когда вы сохраняете, удаляете или обновляете файл на своем компьютере, вы меняете состояние этого файла. Эта концепция похожа на состояния React; вы можете изменить их значения в любой точке приложения.

Следовательно, управление состояниями в React означает обработку различных действий, которые изменяют их значение внутри приложения. Итак, как именно мы управляем состояниями в React?

Важно понимать, что в React управление состоянием заключается в эффективной обработке текущего состояния приложения, и каждое состояние привязано к определенному компоненту.

Как управлять состояниями с помощью хука React useState

Хук useState в React — это самый простой способ управления состояниями. Это позволяет нам создавать и изменять переменные состояния внутри наших компонентов.

Например, рассмотрим компонент «Корзина». Ему необходимо два состояния: одно для текущего товара, добавляемого в корзину, и другое для самой корзины.

Состояние «Корзина» может быть массивом, а элемент — объектом, содержащим цену, название и количество продукта, в зависимости от требований приложения.

React-State-Management React Hooks

Создание состояний и управление ими с помощью хука React useState

Приведенный выше фрагмент кода показывает, как создать состояние с помощью перехватчика useState.

const [state, setState] = useState(<default_value>)

Хук useState возвращает массив из двух элементов. Первое значение в массиве представляет имя состояния и содержит текущее значение состояния. Второе значение — это функция, которая позволяет нам обновлять значение состояния.

Любое состояние, объявленное в вашем приложении, должно иметь значение по умолчанию в зависимости от его типа данных. Это может быть строка, число, объект, массив или даже нулевое значение.

const [stringState, setState] = useState("");
const [objectState, setState] = useState({});
const [objectState, setState] = useState([]);
const [state, setState] = useState(null);

Обновление состояний с помощью хука useState

В предыдущем разделе вы узнали, как объявлять состояния с помощью хука React useState. Здесь я расскажу вам, как их обновить.

Рассмотрим приведенный ниже фрагмент кода:

import { useState } from "react";

const App = () => {
  const [name, setName] = useState("David");
  const changeName = () => setName("Ankur");
  return (
    <div>
      <p>{name}</p>
      <button onClick={changeName}> Change Name</button>
    </div>
  );
};
export default App;

Из приведенного выше фрагмента кода я создал состояние имени с помощью хука useState и установил для него значение по умолчанию «Дэвид».

Функция ChangeName обновляет состояние имени на «Анкур», когда пользователь нажимает кнопку.

Это простая иллюстрация того, как можно использовать хук useState для управления состояниями.

React State Management- Redux

Прежде чем мы продолжим, рассмотрим еще один пример. Предположим, у нас есть страница, на которой отображается счетчик, который позволяет нам увеличивать и уменьшать его значение при нажатии на кнопки.

State Management

import {useState} from 'react'

const App = () => {
  const [counter, setCounter] = useState(0)
 
  const increaseCounter = () => {
  setCounter(count => count + 1)
  }
  const decreaseCounter = () => {
  setCounter(count => count - 1)
}
  return (
    <div>
      <h2>{counter}</h2>
      <div>
        <button onClick={decreaseCounter}> Decrease </button>
        <button onClick={increaseCounter}> Increase </button>
      </div>
    </div>
  )
}
export default App

В отличие от предыдущего примера, функция setCounter принимает параметр и либо добавляет, либо вычитает его значение. Но зачем это нужно?

В тех случаях, когда вы полагаетесь на значение предыдущего состояния для определения его текущего состояния, лучше всего использовать функциональный подход. Это связано с тем, что функция setCounter является асинхронной.

Поэтому, чтобы предотвратить проблемы и обеспечить правильное обновление состояния, рекомендуется использовать функциональный подход.

//👇🏻 increases counter (count is the previous value)
const increaseCounter = () => {
    setCounter((count) => count + 1);
};
//👇🏻 decreases counter
const decreaseCounter = () => {
    setCounter((count) => count - 1);
};

До сих пор вы научились создавать и обрабатывать состояния с помощью хука React `useState`.

Далее давайте обсудим еще один хук React, который чрезвычайно эффективен для управления состояниями в сложных приложениях.

Как управлять состояниями с помощью хука React useReducer

Хук useReducer — еще один мощный инструмент для управления состояниями в вашем приложении. В отличие от useState, который подходит для более простых случаев, useReducer обычно используется при обработке большого количества состояний, особенно в компонентах с многочисленными состояниями в нескольких обработчиках событий.

Хук useReducer можно разделить на четыре ключевых компонента: состояние, функцию редуктора, действие и функцию отправки. Думайте об этом как о машине, состояние которой отражает текущее состояние машины: включена она, выключена, готова к работе или занята.

Функция редуктора действует как мозг машины. Он интерпретирует действия и инструктирует компьютер, что делать на основе различных действий.

Действия аналогичны доступным вам кнопкам, каждая из которых запускает определенное действие. Действие относится к инструкциям, данным машине. Действия могут представлять собой кнопки, которые вы можете нажимать для выполнения различных действий.

Диспетчерская функция выполняет роль панели управления машиной. Он запускает функцию редуктора для выполнения определенной задачи, и вы можете взаимодействовать с функцией диспетчеризации только при обработке задания.

В React состояние — это объект, содержащий все состояния, объявленные в приложении. Функция редуктора напрямую управляет состоянием и возвращает копию результата, а функция диспетчеризации запускает функцию редуктора при возникновении различных событий.

Действие представляет собой объект, содержащий тип и свойство полезной нагрузки. Свойство type определяет точное действие, которое должна выполнить функция редуктора, а полезные данные могут принимать данные от пользователя или других частей приложения.

Управление состояниями с помощью хука useReducer

В этом разделе вы узнаете, как создавать и обновлять состояния React с помощью хука useReducer. Сначала давайте скопируем счетчик с помощью хука useReducer.

import { useReducer } from "react";

const App = () => {
  //👇🏻 reducer function
  const reducer = (state, action) => {
    switch (action.type) {
      case "increase":
        return { counter: state.counter + 1 };
      case "decrease":
        return { counter: state.counter - 1 };
      default:
        return state;
    }
  };
    //👇🏻 declares the useReducer hook
  const [state, dispatch] = useReducer(reducer, { counter: 0 });

  const increaseCounter = () => {
    dispatch({ type: "increase" });
  };

  const decreaseCounter = () => {
    dispatch({ type: "decrease" });
  };

return (
    <div>
      <h2>{state.counter}</h2>
      <div>
        <button onClick={decreaseCounter}>Decrease</button>
        <button onClick={increaseCounter}>Increase</button>
      </div>
    </div>
  );

};

В приведенном выше фрагменте кода вам необходимо объявить хук useReducer, как показано ниже. Хук useReducer принимает два аргумента: функцию редуктора и объект состояния, и возвращает массив, содержащий состояние и функцию отправки.

const [state, dispatch] = useReducer(reducer, { counter: 0 });

Далее вам нужно создать функцию редуктора для выполнения действий увеличения и уменьшения. Хук useReducer достигает этого с помощью оператора переключателя, который проверяет тип выполняемого действия и выполняет это действие.

const reducer = (state, action) => {
    switch (action.type) {
      case "increase":
        return { counter: state.counter + 1 };
      case "decrease":
        return { counter: state.counter - 1 };
      default:
        return state;
    }
  };

Выполните функцию диспетчеризации, чтобы запустить редуктор в зависимости от действия, которое вы хотите выполнить.

const increaseCounter = () => {
    dispatch({ type: "increase" });
  };

  const decreaseCounter = () => {
    dispatch({ type: "decrease" });
  };

Наконец, вы можете получить доступ к значению счетчика из объекта состояния и выполнить функции диспетчеризации, когда пользователи нажимают кнопки.

return (
    <div>
      <h2>{state.counter}</h2>
      <div>
        <button onClick={decreaseCounter}>Decrease</button>
        <button onClick={increaseCounter}>Increase</button>
      </div>
    </div>
  );

Помимо выполнения действий внутри функции редуктора, вы также можете передавать в нее значения, используя объект полезной нагрузки в функции диспетчеризации. Чтобы продемонстрировать это, попробуем увеличить счетчик на 5, когда пользователь нажимает кнопку.

Создайте функцию с именем увеличенияBy5, которая выполняет функцию отправки, которая принимает полезную нагрузку, как показано ниже.

const increaseBy5 = () => {
    dispatch({type: "increaseBy5", payload: {number: 5}})
  }

Наконец, обновите функцию редуктора, чтобы выполнить действие, и добавьте кнопку на страницу. Состояние обновляет свое значение, используя число, переданное в полезную нагрузку.

const reducer = (state, action) => {
    switch (action.type) {
      case "increase":
        return { counter: state.counter + 1 };
      case "decrease":
        return { counter: state.counter - 1 };
      case "increaseBy5":
        return { counter: state.counter + action.payload.number };
      default:
        return state;
    }
  };

React State Management

Одним из основных различий между хуком useReducer и хуком useState является то, что, в отличие от хука useState, вы можете управлять несколькими состояниями внутри хука useReducer. Давайте добавим еще одно состояние, которое переключает свое значение при нажатии кнопки.

Измените перехватчик useReducer, добавив состояние имени.

const [state, dispatch] = useReducer(reducer, { counter: 0, name: "David" });

Поскольку в ловушке useReducer имеется более одного состояния, вам необходимо изменить функцию редуктора, чтобы обновлять состояния с помощью оператора rest.

const reducer = (state, action) => {
    switch (action.type) {
      case "increase":
        return { ...state, counter: state.counter + 1 }
      case "decrease":
        return { ...state, counter: state.counter - 1 }
      case "increaseBy5":
        return { counter: state.counter + action.payload.number }
      case "toggleName":
        return { ...state, name: state.name === "Ankur" ? "David" : "Ankur" };
     
      default:
        return state
    }
  }

Наконец, создайте функцию диспетчеризации, которая переключает состояние имени, когда пользователь нажимает кнопку.

const toggleName = () => {
  dispatch({type: "toggleName" })
}

React State Management

Кроме того, рекомендуется сохранять имена действий внутри объекта и получать к ним доступ через этот объект, чтобы избежать ошибок в именовании. Например, у нас может быть переменная действия, как показано ниже.

const ACTIONS = {
    increase: "increase",
    decrease: "decrease",
    increaseBy5: "increaseBy5",
    toggleName: "toggleName"
  }
const reducer = (state, action) => {
    switch (action.type) {
      case ACTIONS.increase:
        return { ...state, counter: state.counter + 1 }
      case ACTIONS.decrease:
        return { ...state, counter: state.counter - 1 }
      case ACTIONS.increaseBy5:
        return { counter: state.counter + action.payload.number }
      case ACTIONS.toggleName:
        return { ...state, name: state.name === "Ankur" ? "David" : "Ankur"             };
      default:
        return state
    }
  }const toggleName = () => {
  dispatch({type: ACTIONS.toggleName })
}

useState и хук useReducer для управления состояниями

На данный момент вы научились управлять состояниями с помощью хуков useState и useReducer. В этом разделе мы проанализируем оба из них и рассмотрим лучшие случаи их использования.

Хук useState прост в использовании и идеально подходит для приложений с простым управлением состоянием. В таких случаях рекомендуется использовать его, поскольку он требует меньше кода и его легко реализовать. С другой стороны, перехват useReducer лучше всего подходит для приложений, требующих сложного управления состоянием.

Объявление состояний с помощью хука useState:

const [state, setState] = useState(<initial value>)

Объявление состояний с помощью хука useReducer:

const reducer = (state, action) => {
    switch(action.type) {
        //cases
    }
}
const [state, dispatch] = useReducer(reducer, {})

Если у вас есть несколько состояний внутри компонента или состояния со сложными переходами, в этом случае использовать перехватчик useState неэффективно. В таких случаях настоятельно рекомендуется использовать хук useReducer, поскольку он обеспечивает централизованную логику для ваших состояний и эффективно обрабатывает управление состояниями, гарантируя, что оно работает должным образом.

Чтобы продемонстрировать это, давайте создадим приложение to-do, используя хук useReducer. Приложение позволяет пользователям создавать и удалять задачи.

Во-первых, вам нужно объявить хук useReducer с его состоянием по умолчанию. Состояние задач — это массив, содержащий каждый объект задачи, а todoInput представляет каждый элемент, добавленный пользователем.

import { useReducer } from "react";

const App = () => {
    const [state, dispatch] = useReducer(reducer, {
        todos: [
            { id: Math.random(), todo: "Friends hangout" },
            { id: Math.random(), todo: "Team meeting" },
        ],
        todoInput: "",
    });
    return <div>{/**-- App UI--**/}</div>;
};

Приведенный выше фрагмент кода создает два новых состояния — массив todos и todoInput для хранения текущего ввода пользователя.

Затем создайте функцию reducer.

//👇🏻 action names
const ACTIONS = {
    addTodo: "addTodo",
    deleteTodo: "deleteTodo",
    createTodo: "createTodo",
};

//👇🏻 reducer functions
const reducer = (state, action) => {
    switch (action.type) {
        case ACTIONS.addTodo:
            return {
                ...state,
                todos: [
                    ...state.todos,
                    { id: Math.random(), todo: action.payload.todo },
                ],
            };
        case ACTIONS.createTodo:
            return { ...state, todoInput: action.payload.input };
        case ACTIONS.deleteTodo:
            const updatedTodos = state.todos.filter(
                (todo) => todo.id !== action.payload.id
            );
            return { ...state, todos: updatedTodos };
        default:
            return state;
    }
};

Действие addTodo добавляет вновь созданный элемент задачи в массив задач. Действие createTodo обновляет состояние ввода задачи, а действие deleteTodo удаляет выбранный элемент задачи из массива задач, используя его идентификатор.

Верните пользовательский интерфейс приложения из компонента приложения.

import { useReducer } from "react";

const App = () => {
    const ACTIONS = {
        addTodo: "addTodo",
        deleteTodo: "deleteTodo",
        createTodo: "createTodo",
    };

    const reducer = (state, action) => {
        switch (action.type) {
            case ACTIONS.addTodo:
                return {
                    ...state,
                    todos: [
                        ...state.todos,
                        { id: Math.random(), todo: action.payload.todo },
                    ],
                };
            case ACTIONS.createTodo:
                return { ...state, todoInput: action.payload.input };
            case ACTIONS.deleteTodo:
                const updatedTodos = state.todos.filter(
                    (todo) => todo.id !== action.payload.id
                );
                return { ...state, todos: updatedTodos };
            default:
                return state;
        }
    };

    const [state, dispatch] = useReducer(reducer, {
        todos: [
            { id: Math.random(), todo: "Hello todo" },
            { id: Math.random(), todo: "People good?" },
        ],
        todoInput: "",
    });

    return (
        <div>
            <h2> Todo List</h2>
            {state.todos.map((td) => (
                <div key={td.id}>
                    <p>{td.todo}</p>
                    <button onClick={() => handleDeleteTodo(td.id)}>Delete</button>
                </div>
            ))}

            <form onSubmit={handleAddInput}>
                <input
                    type='text'
                    value={state.todoInput}
                    onChange={(e) => handleInputChange(e)}
                />
                <button type='submit'> Add Todo</button>
            </form>
        </div>
    );
};

export default App;

Наконец, создайте функцию, которая обрабатывает входные изменения, и еще две для добавления и удаления элементов из списка дел.

//👇🏻 handles input change
const handleInputChange = (e) => {
    dispatch({ type: ACTIONS.createTodo, payload: { input: e.target.value } });
};
//👇🏻 handles add todo
const handleAddInput = (e) => {
    e.preventDefault();
    //👇🏻 ensures the user's input is not empty
    if (state.todoInput.trim()) {
        dispatch({ type: ACTIONS.addTodo, payload: { todo: state.todoInput } });
        dispatch({ type: ACTIONS.createTodo, payload: { input: "" } });
    }
};
//👇🏻 handles delete todo
const handleDeleteTodo = (id) => {
    dispatch({ type: ACTIONS.deleteTodo, payload: { id } });
};

Функция handleInputChange обновляет состояние todoInput с учетом введенных пользователем данных.

Функция handleAddInput добавляет задачу пользователя в список и сбрасывает поле ввода пустым после того, как пользователь вводит новую задачу.

Функция handleDeleteTodo принимает выбранный идентификатор задачи и удаляет его из списка задач.

React State Management

Как управлять состояниями с помощью Context API

React Context API – это метод управления состоянием, который позволяет нам управлять состояниями в нашем приложении путем передачи props из родительского компонента в его дочерние компоненты.

Например, когда пользователь входит в ваше приложение, вам необходимо настроить работу пользователя в приложении, отображая имя пользователя на нескольких страницах.

Без Context API вам, возможно, придется передавать имя пользователя в качестве реквизита на каждую страницу или родительский компонент, пока оно не дойдет до того компонента, где требуется имя пользователя.

Процесс передачи состояний в качестве реквизитов через несколько родительских компонентов до тех пор, пока они не доберутся до глубоко вложенного компонента, где это необходимо, называется детализацией реквизитов.

React State Management

Этот процесс усложняет поддержку и понимание вашего кода, поскольку родительские компоненты, которым не нужны реквизиты, должны принять его и передать глубоко вложенным компонентам.

Использование Context API помогает решить эту проблему, поскольку позволяет объявить общее состояние в контексте и обернуть все приложение, позволяя компонентам React напрямую обращаться к контексту, не передавая значение с одного уровня компонента на другой.

Context API

Чтобы продемонстрировать, как это работает, давайте добавим страницу входа в приложение списка дел.

Эта страница сохранит имя пользователя в контексте, что позволит нам получить доступ к его значению на других страницах приложения.

Во-первых, учтите, что в нашем приложении есть два компонента: компонент входа и компонент Todo. После входа в приложение имя пользователя отображается вверху страницы Todo. Поэтому мы сохраним имя пользователя в контексте и получим к нему доступ из контекста на странице задач.

Прежде чем мы продолжим, React предоставляет два метода, позволяющие нам использовать Context API:

createContext и useContext. Их названия точно объясняют, для чего они используются.

Далее вам необходимо создать файл AppContext.js, в котором будет храниться имя текущего пользователя.

import { createContext, useState } from "react";

//👇🏻 creates the context
export const AppContext = createContext();

//👇🏻 provides the stored value into other components
export const AppProvider = (props) => {
    const [username, setUsername] = useState("");

    const updateUsername = (value) => {
        setUsername(value);
    };

    return (
        <AppContext.Provider value={[username, updateUsername]}>
            {props.children}
        </AppContext.Provider>
    );
};

Фрагмент кода создает состояние имени пользователя в контексте и делает его доступным для всех компонентов приложения через компонент AppContext.Provider.

Оберните все приложение компонентом AppProvider, чтобы предоставить доступ к его значениям всем остальным компонентам.

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { AppProvider } from "./context/AppContext.jsx";

ReactDOM.createRoot(document.getElementById("root")).render(
    <React.StrictMode>
        <AppProvider>
            <App />
        </AppProvider>
    </React.StrictMode>
);

Создайте форму входа, которая обновляет имя пользователя, хранящееся в контексте приложения.

import { useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AppContext } from "../context/AppContext";

const Login = () => {
    //👇🏻 uses the App Context
    const [username, updateUsername] = useContext(AppContext);
    const navigate = useNavigate();

    const handleNameChange = (e) => {
        updateUsername(e.target.value);
    };
    const handleSignin = (e) => {
        e.preventDefault();
        //👇🏻 navigates to the Todos component
        navigate("/todos");
    };

    return (
        <div>
            <h2>Sign in to your application</h2>
            <form onSubmit={handleSignin}>
                <label htmlFor='username'>Username</label>
                <input
                    type='text'
                    name='username'
                    value={username}
                    onChange={(e) => handleNameChange(e)}
                />
                <button>Sign in </button>
            </form>
        </div>
    );
};

export default Login;

Приведенный выше фрагмент кода принимает имя пользователя и обновляет его значение в контексте.

И наконец, отобразите имя пользователя в компоненте Todos.

import { useContext } from "react";
import { AppContext } from "../context/AppContext";

const Todos = () => {
    const [username, setUsername] = useContext(AppContext);

    //...other state management functions

    return (
        <div className='container'>
            <header>
                <h2> Todo List</h2>
                <h3 className='username'>{username}</h3>
            </header>

            {state.todos.map((td) => (
                <div key={td.id} className='todo_item'>
                    <p>{td.todo}</p>
                    <button onClick={() => handleDeleteTodo(td.id)}>Delete</button>
                </div>
            ))}

            <form className='input_container' onSubmit={handleAddInput}>
                <input
                    type='text'
                    value={state.todoInput}
                    onChange={(e) => handleInputChange(e)}
                    className='inputField'
                />
                <button type='submit'> Add Todo</button>
            </form>
        </div>
    );
};

Приведенный выше фрагмент кода получает имя пользователя из контекста и отображает его на странице.

React State Management

Как управлять состояниями с помощью Redux Toolkit в React

Redux Toolkit – это еще одна альтернатива React Context API, которая позволяет нам управлять состояниями и функциональность аналогична хуку useReducer в React.

С помощью Redux Toolkit вы можете создать в своем приложении хранилище, с которым смогут взаимодействовать все ваши компоненты, аналогично тому, как компоненты получают доступ к контексту в React Context API.

Redux Toolkit также позволяет создавать срезы для ваших состояний, предоставляя упрощенный способ написания редукторов и действий для этого состояния.

Прежде чем вы сможете использовать Redux Toolkit, вам необходимо установить React Redux и Пакеты Redux Toolkit.

npm install react-redux @reduxjs/toolkit

Чтобы проиллюстрировать, как работает Redux Toolkit, давайте изменим страницу входа, чтобы использовать Redux Toolkit для хранения и обновления имени пользователя.

Сначала создайте резервную папку, содержащую фрагмент имени пользователя, как показано ниже.

// In redux/username.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
    value: "",
};

export const usernameSlice = createSlice({
    name: "username",
    initialState,
    reducers: {
        updateName: (state, action) => {
            state.value = action.payload;
        },
    },
});

export const { updateName } = usernameSlice.actions;

export default usernameSlice.reducer;

Из фрагмента кода функция createSlice принимает имя состояния, его начальное значение и все функции редуктора, связанные с состоянием в объекте. Обязательно экспортируйте редукторы в конец файла.

Создайте в своем приложении файл store/store.js, содержащий все состояния Redux.

import { configureStore } from "@reduxjs/toolkit";
import userNameReducer from "../redux/username";

export const store = configureStore({
    reducer: {
        username: userNameReducer,
    },
});

Наконец, сделайте хранилище доступным для всех компонентов, обернув все приложение компонентом Provider из React Redux.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { Provider } from "react-redux"
import { store } from './store/store.js'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
)

Взаимодействие с набором инструментов Redux

Redux Toolkit предоставляет два хука, которые позволяют нам взаимодействовать с состояниями. Это крючки useSelector и useDipatch.

Хук useSelector позволяет нам выбирать определенное состояние, объявленное в Redux, а хук useDispatch позволяет нам запускать различные функции редуктора.

Выберите состояние имени пользователя и обновите его значение, когда пользователь входит в приложение.

import { useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { updateName } from "../redux/username";

const Login = () => {
    //selects the username Redux state
    const username = useSelector((state) => state.username.value);
    //initializes the useDispatch hook
    const dispatch = useDispatch();
    const navigate = useNavigate();

    const handleNameChange = (e) => {
        //updates the username state
        dispatch(updateName(e.target.value));
    };
    const handleSignin = (e) => {
        e.preventDefault();
        navigate("/todos");
    };

    return (
        <div className='mid_container'>
            <h2>Sign in to your application</h2>
            <form onSubmit={handleSignin} className='loginForm'>
                <label htmlFor='username'>Username</label>
                <input
                    type='text'
                    name='username'
                    value={username}
                    onChange={(e) => handleNameChange(e)}
                    className='inputField'
                />
                <button>Sign in </button>
            </form>
        </div>
    );
};

Приведенный выше фрагмент кода выбирает значение имени пользователя из состояния Redux и обновляет его с помощью перехватчика useDispatch, когда пользователи вводят свое имя пользователя.

//selects the username value
const username = useSelector((state) => state.username.value);
const dispatch = useDispatch();
const handleNameChange = (e) => {
  // updates the username state
  dispatch(updateName(e.target.value));
};

Как использовать URL-адреса для хранения состояний в React

Этот метод довольно необычен, но очень полезен в тех случаях, когда вы хотите сохранить состояния или добавить их в закладки в своем приложении. Например, если вы хотите, чтобы ваши пользователи делились URL-адресом страницы, и когда другие пользователи посещают страницу, они должны видеть один и тот же пользовательский интерфейс.

Предположим, вы создаете веб-сайт электронной коммерции, и пользователь выбирает вариант продукта, которым он хотел бы поделиться с другом. Как вы гарантируете, что друг, посетив страницу, увидит тот же просмотр?

Метод управления состоянием URL-адресов — лучшее решение. Он изменяет URL-адрес страницы на основе данных, предоставленных пользователем. Чтобы продемонстрировать, как это работает, давайте добавим функцию поиска в приложение списка дел.

Прежде чем мы продолжим, вам необходимо установить пакет React Router.

npm install react-router-dom

Пакет React Router предоставляет хук useSearchParams, который позволяет нам изменять и сохранять данные в URL-адресе страницы.

import { useSearchParams } from "react-router-dom";

const TodoList = () => {
    const [searchParams, setSearchParams] = useSearchParams({ search: "" });

    const filterText = searchParams.get("search");

    return <div>{/**--App UI--**/}</div>;
};
<блок-цитата>

В приведенном выше фрагменте кода к URL-адресу страницы добавляется параметр запроса `search`, и он становится примерно таким: http: //localhost:5173/todos?search=team+hangout

Затем добавьте поле формы фильтра на страницу списка дел, чтобы пользователи могли фильтровать задачи по их имени. Введенные пользователем данные также добавляются к URL-адресу страницы по мере обновления поля ввода.

const TodoList = () => {
    //...other state functions
    return (
        <div className='container'>
            <header>
                <h2> Todo List</h2>
                <h3>{username}</h3>
            </header>
            {/*--filter todo form--*/}
            <form>
                <h2>Filter Todo</h2>
                <input
                    type='text'
                    value={filterText}
                    onChange={(e) => handleFilter(e)}
                />
            </form>

            {state.todos.map((td) => (
                <div key={td.id}>
                    <p>{td.todo}</p>
                    <button onClick={() => handleDeleteTodo(td.id)}>Delete</button>
                </div>
            ))}

            <form onSubmit={handleAddInput}>
                <input
                    type='text'
                    value={state.todoInput}
                    onChange={(e) => handleInputChange(e)}
                />
                <button type='submit'> Add Todo</button>
            </form>
        </div>
    );
};

Создайте функцию handleFilter, которая фильтрует задачи, обновляет URL-адрес страницы и возвращает только те задачи, которые соответствуют вводу пользователя.

const handleFilter = (e) => {
    const filteredResult = state.todos.filter((item) =>
        item.todo.toLowerCase().startsWith(e.target.value.toLowerCase())
    );
    setSearchParams(
        (prev) => {
            prev.set("search", e.target.value);
            return prev;
        },
        { replace: true }
    );
    if (filteredResult.length !== 0) {
        dispatch({ type: ACTIONS.setTodo, payload: { todos: filteredResult } });
    }
};

В заключение отметим, что хук useSearchParams предоставляет простой способ эффективного управления состояниями и обеспечивает лучший пользовательский опыт для ваших пользователей.

Выводы и основные выводы

На данный момент вы научились управлять состояниями с помощью хуков useState и useReducer, React Context API, Redux Toolkit и URL-адреса страницы.

Вот несколько вещей, на которые следует обратить внимание:

  • Используйте хук useState для простого управления состоянием.
  • Используйте useReducer, если у вас есть множество состояний внутри компонента или для состояний со сложными переходами.
  • Используйте React Context API или Redux Toolkit для приложений, в которых нескольким компонентам требуется или изменяет общее состояние.
  • Используйте метод URL-адреса для хранения состояний, особенно если вам нужно сохранить состояния даже после обновления страницы.

Спасибо за чтение. Если вам нравится этот блог и вы хотите узнать больше о ReactJS и JavaScript, начните читать некоторые из моих последних статей.

* Зачем изучать React * Положительные стороны React * Распространенные вопросы по JavaScript, которые я задавал на собеседованиях * Простой и эффективный способ обучения и amp; Практикуйте JavaScript. * Как изучать ReactJS в 2024 году * Современный JavaScript * Руководство по созданию проекта с помощью Vite< /сильный> * Как использовать React Hooks * Как использовать и проверять формы в React * Изучите React – Руководство по ключевым понятиям. Полное руководство по FreeCodeCamp< /strong>

Теперь пришло время сделать следующий шаг: подписаться на мою информационный бюллетень и подписаться на меня на Твиттер.

bytesizedbets

Информационный бюллетень о карьере, бизнесе, писательстве и жизненных советах для инженеров


Также опубликовано здесь.


Оригинал