发布于 2026-01-06 11 阅读
0

如何使用 Redux 管理 React 应用中的状态。

如何使用 Redux 管理 React 应用中的状态。

在本教程中,你将使用 Redux 管理 React 应用的状态。Redux 可以帮助你在一个对象中跟踪和管理整个应用的状态,而无需将状态和逻辑放在顶层组件中。

你将使用 Redux 构建一个集中管理状态和逻辑的待办事项应用程序。

完成本教程后,您将了解:

  • Redux是什么,以及使用Redux进行状态管理的好处。

  • 在待办事项应用中理解和使用 Redux 的概念,例如 store、reducer、actions 等。

本教程分为两部分。第一部分讲解关键概念、Redux架构以及Redux的基本用法。第二部分,我们将使用Redux构建一个待办事项应用,用于状态管理。

先决条件

为了更好地学习本教程,您应该熟悉以下内容:

  • JavaScript 中的函数

  • 熟悉 React 术语:状态、JSX、组件、属性和 Hooks

  • 构建一个基本的 React 应用

国家管理概论

React 使开发者能够轻松构建复杂的用户界面。为了给 UI 添加交互性,React 组件需要访问数据。这些数据可以是来自 API 端点的响应,也可以是应用内部定义的数据。当用户点击按钮或在输入框中输入内容时,这些数据会根据交互事件进行更新。

在 React 组件内部,数据存储在一个object名为 `data` 的变量中state。每当state数据发生变化时,组件都会重新渲染,React 会更新屏幕以在 UI 中显示新数据。

在 React 应用中,多个组件可能需要访问状态。因此,状态需要得到有效管理。有效的状态管理意味着能够在应用中存储和更新数据。

Redux是什么?

Redux 是一种用于管理和更新应用程序状态的模式和库,它使用称为“action”的事件。它充当一个集中式状态存储,用于存储需要在整个应用程序中使用的状态,并通过规则确保状态只能以可预测的方式更新。

使用 Redux,您可以拥有一个中央状态存储来维护、更新和监控应用程序的状态。这意味着,我们的组件可能不再需要自己的状态。状态将集中在一个位置,并且可以被应用程序中的多个组件访问。

Redux解决了什么问题?

一个基本的 React 应用可以分为以下几个部分:

  • 状态:应用程序的当前状态

  • 视图:应用程序的用户界面

  • 操作:当应用程序中发生事件时更新状态的函数(通常称为事件处理程序)。

应用程序中的每个组件都可以拥有状态。然而,如果多个组件需要访问相同的数据,就会出现问题。为了解决这个问题,我们称之为“状态提升”。状态提升是指将状态从子组件移动到其父(顶层)组件的过程。通过这种方法,您可以轻松地在多个子组件之间共享状态。

LiftingStateReact

然而,“提升国家地位”也有其弊端:

  • 这样做会使你的代码变得复杂:将状态提升到父组件可能会在组件中添加大量样板代码。状态必须从父组件传递到子组件,这会导致代码冗余prop-drilling。此外,状态也会在父组件中更新。

  • 它会影响性能:当你将状态提升到组件层级时,状态改变时需要重新渲染的组件数量就会增加。这可能会影响性能,尤其是在移动设备上。

在大型单页应用程序中,我们的代码需要管理更多状态。这些状态可能包括服务器响应和缓存数据,以及尚未持久化到服务器的本地创建数据。最终,您将无法控制状态的更新时间、原因和方式,从而导致难以重现错误或添加新功能。

更好的方法是从父组件中提取共享状态,并将它们放在组件树之外的集中位置。

这种方法更好,因为:

  • 它省去了螺旋桨钻孔。

  • 无论组件位于何处,您都可以从父组件内的任何组件触发操作,并且可以修改其状态。

这就是 Redux 背后的理念。它帮助开发者管理全局状态(应用程序的许多部分都需要的状态),并使所有组件都能访问该状态,无论它们嵌套有多深。

Redux 的第一条规则是,应用程序中所有可以修改的内容都应该用一个名为 `Reux` state 或 `Reux.get`的单一对象来表示。 state tree.

使用 Redux 时需要了解一些关键术语。为了便于理解,我们首先会用一个类比来解释 Redux。之后,我们将在接下来的章节中对这些术语进行定义。

Redux 类比

想象一下,你是一家大型餐厅的管理合伙人。为了更好地管理餐厅,你决定密切关注餐厅的运营状况。

您可能需要追踪以下内容:

  • 各种原料的库存情况

  • 财务状况(每周收入和支出模式)

  • 受雇厨师人数

  • 雇佣的女服务员人数

  • 每周客户等

把所有这些信息都记在脑子里会很麻烦。所以,你应该把它们保存在一个叫做“存储库”的中心位置(redux store)。

您雇佣了一名服务员reducer),他是唯一可以更新商店信息的人。

一些股东components)依赖餐厅的状态(数据)来更新他们的投资组合(UI)。这些股东只能访问数据,而不能修改数据。

现在假设股东们聘请了一位新厨师,需要更新门店的数据。由于他们无法直接更新数据,股东可以dispatch向服务员发送一条包含新信息的便条reducer服务员随后会将门店的旧数据更新为最新信息

每当数据更新时,其他股东都会收到通知(subscribers),他们可以更新自己的投资组合(UI)。

ReactRedux

了解 Redux 术语

以下是一些需要熟悉的新术语:

行动

Redux 的第二条规则是状态树 state 是只读的。你只能通过发送 `removeState` 来修改状态树 action这确保了视图和网络回调都不会直接写入状态。相反,它们表达的是转换状态的意图。

换句话说,action这是更改应用程序的唯一推荐方法state

操作描述了应用程序中发生的情况。它是一个 JavaScript 对象,作为参数传递给,并包含更新store所需的信息storestate

在不同的应用程序中,所需参数action各不相同。例如,在计数器应用程序中,您只需要以下参数:actions:

  • 数量增加

  • 数量减少

在待办事项应用中,您可能会看到以下内容actions

  • 已添加待办事项

  • 已删除待办事项

  • 完成待办事项

  • 筛选待办事项等。

使用 Redux,因为我们将状态state与组件分离,所以组件并不知道状态是如何变化的。它们只关心需要发送一个事件action

该操作object有一个type属性,您可以在其中指定组件中发生的事件。这意味着每当发生事件时,事件处理函数都会分发一个action包含已发生事件信息的回调,以帮助更新statestore 中的数据。

它还action object具有一个payload属性。任何关于事件的新数据都将存储在该属性中payload。例如,当我分发“addedTodo”action事件时type,该属性payload可以包含新的待办事项及其 ID。

以下是一些action对象示例:


//action 1
const addTodoAction = {
  type: 'todos/todoAdded', //what happened
  payload: {todoID, newTodo} //data
}
//action 2
const getOrder = {
type: 'orders/getOrderStatus', //what happened
payload: {orderId, userID} //data
}
Enter fullscreen mode Exit fullscreen mode

行动创造者

这些action creators函数会返回action对象。由于它们action creators包含可在应用程序多个实例中使用的逻辑,因此您可以向其传递一些parameters可在action对象中访问的参数。

以下是一些示例action creators

//example 1
function addTodo(todo){
//return action object
return {
  type: 'todos/addTodo',
  payload: todo // what happened
    }
}
//example 2
function getOrders(orderID, userID){
//return action object
  return {
       type: 'orders/getOrderStatus',
       payload: {orderId, userID} //what happened
   }
}
Enter fullscreen mode Exit fullscreen mode

减速器

Areducer是一个纯函数,它接受当前状态state和一个新状态action作为参数arguments,并返回更新后的状态state。之所以称之为 reducer,是reducer因为与方法类似Array.reduce(),Redux reducer会将一系列操作随时间推移简化为一个单一状态。

reducer 应该是一个纯函数。纯函数是指对于相同的输入,它只会返回相同的输出。它不会改变或修改全局状态或任何其他函数的状态。

这意味着:

  • reducer 函数不允许修改当前值state。相反,它们必须复制当前值state,然后更新复制的值。

  • reducer 函数不应该通过读取数据库来更新状态。

  • reducer 函数不应该调用任何第三方 API

以下是 reducer 函数的语法:

const myReducer = (state, action) => newState
Enter fullscreen mode Exit fullscreen mode

reducer 函数内部的逻辑如下:

  • 在函数体中,我们检查该action.type属性。

  • 如果type操作与您定义的内容匹配,您将复制该操作state,并使用来自该操作的新值修改该状态。action.payload

  • 如果结果action.type与您定义的任何内容都不匹配,则返回现有结果。state

以下是一个todoReducer函数示例:

const intialTodo = [{id:1, todo:""}]

const todoReducer = (state = initialTodo, action)=>{
if(action.type === "todos/AddedTodo"){
  return [...state, todo: action.payload]
}else{
return state
 }
}
Enter fullscreen mode Exit fullscreen mode

以下是目前的情况:

  • if语句中验证是否action.type与右侧的表达式(action.type === "todos/AddedTodo")匹配。

  • 如果确实如此,那么我们使用扩展运算符 ( ...) 创建一个副本state,并使用从新待办事项数据中获取的数据更新该副本。action.payload

  • 否则,我们返回前一个值。state

Redux 的第三个原则是,为了描述状态变化,你需要声明一个函数,该函数接受应用程序的先前状态、要分发的 action,并返回应用程序的下一个状态。

店铺

Astore是包含整个state应用程序的对象。它是数据的中心位置,也是数据更新的地方。

store有三种主要方法:

  • getState()返回state应用程序的当前状态

  • dispatch(action)这是指示组件向 store 发送操作以更改state应用程序的方法。

  • subscribe(listener)subscribe方法允许组件监听数据变化。它接受一个函数listener作为callback参数,该函数可以帮助您:

    • 更新用户界面以反映当前状态
    • 当状态改变时,执行副作用或其他需要执行的任务。

下面是一个如何store在 Redux 中创建的示例。

//store.js

//import your root reducer
import rootReducer from "./rootReducer"
//import createStore from redux
import {createStore} from "redux"

//create the store
const store =createStore(rootReducer)
Enter fullscreen mode Exit fullscreen mode

派遣

Dispatch 用于action向我们发送消息store。这是更改state我们应用程序的唯一方法。

要更新状态state,您需要调用该store.dispatch()方法。当dispatch()该方法被调用时,store 将执行 reducer(reducers 可以访问当前状态state和一个响应action作为输入,并执行一些逻辑)。然后,store 会使用 reducer 的输出更新其状态。

store.dispatch()方法接受action对象作为参数。

store.dispatch({ type: 'todo/addedTodo' })
Enter fullscreen mode Exit fullscreen mode

例如,在上面的代码片段中,每当用户输入一个新的待办事项时,你都会将操作分发给 `store` 。因为`store` 内部store有一个函数,它将使用分发的操作来确定新状态的逻辑。reduceraction.type

选择器

选择器是帮助你从中提取特定数据的函数state。它接受state一个参数,并返回要从中检索的数据state

您将selector在组件中使用它来从状态中获取特定数据。

const selectLatestTodo = state => state.data //selector function

const currentValue = selectLastestTodo(store.getState())
console.log(currentValue)
// Buy milk
Enter fullscreen mode Exit fullscreen mode

Redux架构示意图

在本节中,我们将使用所有学过的术语来解释我们的应用程序中的数据流,以及当状态改变时 UI 如何重新渲染。

我们来看看 Redux 的配​​置:

  • 创建 Reduxstore

  • 定义reducer逻辑并将reducer函数传递给 store。该函数reducer接受 ` stateand`action对象作为参数。

  • 它将运行函数store中的逻辑。reducer

  • reducer 函数返回的值将成为应用程序的初始状态。

  • 组件挂载时,会连接到 store,获取初始状态,并使用该状态显示 UI。由于组件已连接到 store,因此它可以访问任何状态更新。

正在更新状态:

  • 应用中发生了一个事件。例如,添加了一个待办事项。

  • 该组件将请求分发给actionRedux。store

  • store会重新运行该reducer函数。它可以访问之前的状态state(即action对象),并返回更新后的状态。

  • 它会将状态变化store 通知所有连接的组件。

  • 每个 UI 组件都会检查是否需要使用更新后的状态。

  • 如果满足条件,它会使用新状态重新渲染用户界面,并更新屏幕上的内容。

ReduxArchi

创建storesubscribing调度actions

在本节中,我们将学习如何创建应用store以及dispatch对商店的操作。

Redux store 将我们应用程序的配置state、数据reducer和状态整合在一起action。它是应用程序状态的中心位置。

其功能store是:

  • 保持应用程序的当前状态。

  • 允许访问当前状态

  • 允许更新状态

  • 调度行动

  • 订阅变更

创建商店

使用createStore()Redux 库中的方法来创建store。该方法接受一个reducer函数作为参数。

以下是创建商店的代码片段:

//store.js
import { createStore} from 'redux'

const store  = createStore(rootReducer)
Enter fullscreen mode Exit fullscreen mode

接下来,你需要将“根 reducer”函数传递给它createStore()。根 reducer 会将应用程序中的所有其他 reducer 合并在一起。

要创建根 reducer,你需要combineReducer()从 Redux 库导入相应的方法。该方法combineReducer可以帮助你组合所有不同的 reducer 函数。它接受一个objectreducer 函数对象作为参数。key该对象的键将成为根状态对象的键,而值则是相应的 reducer 函数。

以下是如何创建的示例rootReducer

import { combineReducers } from 'redux';

const reducers = {
  user: userReducer,
  cart: cartReducer,
  orders: ordersReducer,
};

const rootReducer = combineReducers(reducers);
Enter fullscreen mode Exit fullscreen mode

现在,你已经学会了如何……

  • 创建店铺

  • 向 store 添加根 reducer

接下来,您将学习如何获取商店的初始状态并将操作分发到商店。

派往actionsstore

要更新state应用程序,组件需要分发操作。

以下是具体操作方法:

  • 将其导入store到您的应用程序中

  • 调用这些store.dispatch()方法并传递action对象。

//actions object
const addTodo = {
  type: 'todos/todoAdded',
  payload: "Buy milk"
});

const completeTodo = {
  type: 'todos/todoRemoved',
  payload: 2 // id of the todo to complete
}
//dispatch the action to update the state 
store.dispatch(addTodo)
store.dispatch(completeTodo)
Enter fullscreen mode Exit fullscreen mode

订阅商店

使用此subscribe()方法订阅应用商店。该subscribe()方法会监听state应用商店的更改。这将帮助您更新 UI 以反映当前商店state,执行副作用,或执行任何需要在商店state更改时完成的任务。

下面的代码片段演示了如何监听更新,并将最新状态记录到控制台:

const subscription = store.subscribe(() => {
  // Do something when the state changes.
  console.log('State after dispatch: ', store.getState())
});
Enter fullscreen mode Exit fullscreen mode

将 Redux 添加到 React 应用中

在本节中,您将运用所学的概念,构建一个具有基本功能(添加、删除和完成待办事项)的待办事项应用程序,同时使用 redux 进行state管理。

由于我们之前已经介绍过相关概念,因此不会深入探讨每个具体实现方法。

以下是具体步骤:

  1. 设置您的 React 项目并安装所需的依赖项

  2. 为用户界面创建待办事项组件。

  3. 创建一个 Reduxstore来跟踪和管理state你的应用程序

  4. 定义reducer逻辑并连接到商店

  5. 调度actions员更新state

  6. 读取数据store

项目代码仓库位于此处。它包含多个分支,分别对应我们将要实现的每个主要步骤。

让我们开始吧

步骤 1:设置您的项目

按照以下步骤在项目目录中创建一个 React 应用:

  • 使用 Vite 从基本模板创建项目,在终端中运行以下命令:

    npm create vite@latest my-react-app --template react
    // Replace "my-react-app" with the name of your project.
    
  • 在您的文件中安装redux及其react-redux依赖项package.json。运行命令

    npm install redux react-redux --save
    

    这将安装核心 Redux 架构,并简化 React 应用与 Redux 的连接。

  • 使用以下命令运行应用程序npm run dev

步骤 2:创建待办事项组件

以下是我们应用程序的用户界面。

TodoRedux

现在,让我们创建所需的组件。

  • 在“src”目录中创建一个名为“components”的文件夹

  • 创建应用程序用户界面所需的组件包括:

    • <TodoHeading/>包含标题文本
    • <TodoInput/>输入待办事项的输入框
    • <TodoItem/>显示单个待办事项,带有删除和完成按钮
    • <TodoList/>显示待办事项列表。

成分

步骤 3:创建store

接下来,我们需要创建一个控制器store来跟踪和管理整个state应用程序。我们使用createStore()Redux 中的方法来实现这一点。

请按照以下步骤操作:

  • 在应用的根目录下创建一个名为“store”的文件夹。

  • store.js在“store”文件夹中创建一个文件

  • createStore从 Redux导入该方法

  • 调用该createStore()方法,并将作为参数传递todoReducer(我们将在下一步中定义它)。

  • 导出store以便在 React 应用中使用

//store/store.js
import { createStore } from "redux";
import todoReducer from "../reducer/todoReducer";

const store = createStore(todoReducer);

export default store;
Enter fullscreen mode Exit fullscreen mode

步骤 4:定义reducer函数

我们将在一个文件中定义 reducer。ReducertodoReducer.js是包含更新状态所需逻辑并返回新状态的函数。它todoReducer.js还将包含应用程序的初始状态。

按照以下步骤定义reducer函数:

  • 创建一个todoReducer.js内部“reducer”文件夹

将以下代码片段添加到文件中

//state object
const initialState = {
  todos: [
    {
      id: 1,
      item: "Learn redux fundamentals",
      completed: false,
    },
    {
      id: 2,
      item: "Build a todo-app",
      completed: false,
    },
  ],
};

//define the reducer logic
const todoReducer = (state = initialState, action) => {
  switch (action.type) {
//logic to add a new todo
    case "todos/addedTodo":
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };
//logic to delete a todo
    case "todos/deleteTodo":
      return {
        ...state,
        todos: state.todos.filter((todo) => todo.id !== action.payload),
      };
// logic to complete a todo
    case "todos/completeTodo":
      return {
        ...state,
        todos: state.todos.map((todo) => {
          if (todo.id === action.payload) {
            return {
              ...todo,
              completed: !todo.completed,
            };
          } else {
            return todo;
          }
        }),
      };
    default:
      return state;
  }
};

export default todoReducer;
Enter fullscreen mode Exit fullscreen mode

在上面的代码中:

  • 我们添加了应用程序的首字母state。它预先填充了一些array待办事项,以便在应用程序渲染时显示一些虚拟数据。

  • 我们定义该todoReducer函数。该函数接受 ` stateand`action对象作为参数。

  • 在函数体中,我们实现了一个switch语句。根据表达式(action.type),每个语句都包含一个逻辑,case用于决定如何state更新和返回值。

  • 最后,我们exporttodoReducer其作为参数传递给该createStore()方法(如前所述)。

步骤 5:将Provider组件包裹在你的应用周围

Provider组件使 Reduxstore可供任何需要访问它的嵌套组件使用store

由于 React Redux 应用中的任何 React 组件都可以连接到 store,因此大多数应用都会Provider在顶层渲染一个组件,并将整个应用的组件树包含在其中。

以下是如何将根组件包裹在……之中Provider

  • 导入storemain.jsx

  • Provider从“react-redux”导入组件

  • 将根组件包裹<App/>Provider

  • Provider接受一个props,其值为store导入的内容。store

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

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <Provider store={store}> 
      <App />
    </Provider>
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

在上面的代码中,我们<Provider/><App/>组件进行了包装,以使所有嵌套组件都能访问该组件。store

useSelector接下来,我们将使用钩子从商店读取并显示数据。

useSelector步骤 6:使用钩子读取和显示待办事项

React-Redux 拥有自定义的 Hook,你可以在组件中使用这些 Hook。该useSelectorHook允许 React 组件从 Redux store 中读取数据。它接受一个选择器函数,该函数以整个 Redux store 状态作为参数,从状态中读取某个值,并返回该结果

请按照以下步骤读取和显示数据:

  • useSelector从“react-redux”导入

  • 调用该useSelector()方法。它接受一个选择器函数作为回调函数。

  • todos从……返回state

以下代码演示了如何todos从我们的商店读取数据。

//components/TodoList.jsx
import React from "react";
import { useSelector } from "react-redux";
import TodoItem from "./TodoItem";

const TodoList = () => {
//callback function
  const selectTodos = (state) => state.todos; 
//extract the todos
  const returnedTodos = useSelector(selectTodos);

  const displayTodos = returnedTodos.map((todo) => (
    <TodoItem key={todo.id} todo={todo} />
  ));
  return <div>{displayTodos}</div>;
};

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

让我们来理解上面的代码:

  • 组件首次<TodoList/>渲染时,该useSelector钩子函数将执行selectTodos回调函数。

  • 返回的值selectTodos将由钩子返回,useSelector供我们的组件使用。

  • 它将保存与Redux store 状态内部const returnedTodos相同的数据。state.todos

  • 我们使用 JavaScriptmap()方法遍历每个待办事项,并显示单个待办事项。

  • useSelector 会自动订阅Redux store。因此,每当actiondispatch 一个事件时,它都会调用该selectTodos函数。如果该函数返回的值 selectTodos 已更新, useSelector 则会强制 TodoList 组件使用新数据重新渲染。

我们知道如何从数据存储中读取和显示数据store。接下来,我们将学习如何从组件分发操作来更新数据存储。

useDispatch步骤 5:使用钩子分发操作

该钩子提供了对分发更新所需的方法useDispatch的访问dispatchactionsstate

我们可以调用const dispatch = useDispatch()任何需要分发操作的组件,然后dispatch(someAction)根据需要进行调用。

TodoInput组件中,我们来发送一个 action 来添加一个新的待办事项:

  • useDispatch从“react-redux”导入

  • 调用该useDispatch()方法。它返回dispatch函数。

  • 输入并提交新的待办事项

  • 调用该dipatch()方法addTodo并传递action对象

    //components/TodoInput.jsx
    import React, { useState } from "react";
    import { useDispatch } from "react-redux";
    
    const TodoInput = () => {
      const [todo, setTodo] = useState("");
      const dispatch = useDispatch();
    
      const onInputTodo = (e) => {
        setTodo(e.target.value);
      };
      //handle submission of todo
      const handleTodoSubmit = (e) => {
        e.preventDefault();
        addTodo(); // addTodo 
        setTodo("");
      };
    //action creators
      const addTodo = () => {
    //dispatch action to add a todo
        return dispatch({
          type: "todos/addedTodo",
          payload: { id: Math.floor(Math.random() * 20) + 1.1, item: todo },
        });
      };
      return (
        <div>
          <form className="todo_form_container" onSubmit={handleTodoSubmit}>
            <input
              className="todo_input"
              type="text"
              placeholder="Enter your todo"
              value={todo}
              onChange={onInputTodo}
            />
            <button className="todo_btn">Add Todo</button>
          </form>
        </div>
      );
    };
    
    export default TodoInput;
    

在上面的代码中,提交新的待办事项时:

  • handleTodoSubmit函数执行该addTodo()函数

  • 它将对象分addTodo()发给函数以进行更新。actiontodoReducerstate

因为我们已经导入了useSelector钩子,所以我们可以轻松地向商店状态添加新的待办事项,并且它会反映在用户界面中。

以下是我们目前为止所完成的工作。

  • 创建store

  • 将 `<store>` 标签包裹<Provider store={store}>在顶级<App>组件周围,以使所有其他组件都能访问和更新存储。

  • 调用useSelector钩子函数以在 React 组件中读取数据

  • 调用useDispatchhook 来分发 React 组件中的 action

点击“删除”和“完成”按钮后执行相应操作

TodoItem组件中,我们现在可以点击“删除”和“完成”按钮。点击这些按钮后,我们会分发删除和完成待办事项的操作。这些操作在 ` onDeleteand`onComplete操作创建器中处理。

代码片段如下:

//components/TodoItem.jsx
import { useDispatch } from "react-redux";

const TodoItem = ({ todo }) => {
  const dispatch = useDispatch();
  //delete a todo
  const onDelete = (id) => {
    return dispatch({
      type: "todos/deleteTodo",
      payload: id,
    });
  };
  //complete Todo
  const onComplete = (id) => {
    return dispatch({
      type: "todos/completeTodo",
      payload: id,
    });
  };
  return (
    <div>
      <h3 className={`todo${todo.completed ? "Completed" : ""}`}>
        {todo.item}
      </h3>
      <div>
        <button onClick={() => onComplete(todo.id)}>Complete</button>
        <button onClick={() => onDelete(todo.id)}>Delete</button>
      </div>
    </div>
  );
};

export default TodoItem;
Enter fullscreen mode Exit fullscreen mode
  • 点击“删除”和“完成”按钮分别调用 `delete` 和 `complete` 函数。`delete`函数会向 ` onDelete()create`对象发送删除指定项的操作,而 `complete` 函数会向 `create` 对象发送完成所选项的操作。onCompleteonDeletetodoReduceronCompletetodoReducer

Redux 与 Context API 的比较

Redux 和 Context API 的区别在于它们管理状态的方式。Redux 将状态集中存储在一个中央 store 中。而 Context API 则在组件级别处理状态更新,因为状态更新发生在每个组件内部。

你可能会问,既然这样可以避免使用问号,为什么不使用useContextContext API 中的 hook 来将状态传递给多个组件呢prop drilling

如果某个状态会影响多个组件,或者应用中的所有组件都需要它,你可以使用useContext钩子来管理它state。这样可以避免 props 层层传递,并使所有组件都能轻松访问数据。

然而,使用以下方法也存在一些缺点useContext

  • useContext钩子设置较为复杂:在构建企业级应用时,多个组件可能需要访问state该钩子,因此您可能需要使用contextAPI 创建多个上下文,并为每个上下文提供应用不同方面所需的数据。例如,您将创建

    • 身份验证上下文:方便用户进行身份验证
    • 主题上下文:用于更改主题。例如,启用深色模式。
    • 表单上下文:用于将表单数据传递给表单组件等。

    这种现象可能导致需要创建多个上下文来满足特定需求,从而导致应用程序中出现深度嵌套的上下文提供程序组件。

语境

  • 其次,useContext它并未针对状态频繁变化的企业级应用进行优化。这将降低应用的性能。

  • 最后,在使用时useContext,UI 逻辑和状态管理将位于同一个组件中。

以下是一些你可能使用 Redux 的场景useContext

  • 您的应用程序中有很多状态,而且这些状态在应用程序的很多地方都是必需的。

  • 应用程序状态会随时间频繁更新

  • 更新该状态的逻辑可能很复杂。

  • 该应用的代码库规模中等或较大,可能由多个开发人员共同开发。

结论

在本教程中,您使用 Redux 管理了 React Todo 应用的状态。接下来,我们将学习如何使用Redux Toolkit管理状态。Redux Toolkit 可以简化编写优秀 Redux 应用的过程,并加快开发速度。此外,您还将学习 Redux DevTools,它可以帮助您追踪应用状态何时、何地、为何以及如何发生变化。

文章来源:https://dev.to/efkumah/how-to-manage-state-in-a-react-app-using-redux-5pc