首页 > web前端 > js教程 > 正文

了解 Redux:初学者综合指南

王林
发布: 2024-08-24 11:06:02
原创
787 人浏览过

Understanding Redux: A Beginner

简介:什么是 Redux 以及为什么我们需要它?

随着 Web 应用程序变得越来越复杂,管理状态变得越来越具有挑战性。如果您发现自己陷入了不可预测的状态变化和难以跟踪的数据流的网络中,那么您并不孤单。这就是 Redux 发挥救星作用的地方。

Redux 是 JavaScript 应用程序的状态管理库,以其有效性而闻名,尤其是与 React 一起使用时。通过提供可预测且集中的方式来管理应用程序状态,Redux 简化了跟踪数据如何随时间变化以及应用程序的不同部分如何相互交互的过程。

但是为什么 Redux 是必要的呢?在任何大型应用程序中,状态更改都可能发生在多个位置,因此很难查明特定数据在何处以及如何更改。调试和维护此类应用程序可能会成为一场噩梦。 Redux 通过将整个应用程序的状态存储在一个称为存储的集中位置来解决这些挑战。这种集中式方法不仅简化了状态管理,还增强了应用程序的可预测性和可测试性。

本指南将带您详细了解 Redux,从理解其核心概念到在 React 应用程序中设置和使用它。读完本文后,您将牢牢掌握 Redux,并有能力将其应用到您的项目中。

Redux 的核心概念

要真正理解 Redux,必须熟悉三个基本概念:store、action 和 reducer。让我们更深入地了解每个概念。

1. 商店:唯一的真相来源

Redux 的核心是存储,它是一个集中存储库,保存应用程序的整个状态。商店是应用程序数据的唯一真实来源。无论您的应用程序变得有多大或多复杂,所有状态都存储在一个位置,从而更易于管理和调试。

将商店想象成一个巨大的 JavaScript 对象,其中包含应用程序运行所需的所有信息。无论是用户数据、UI 状态还是服务器响应,所有内容都存储在该对象中。这种集中式方法与在各个组件内本地管理状态的传统方法形成鲜明对比,这可能会导致跟踪状态更改的不一致和困难。

Redux 中的存储是不可变的,这意味着一旦设置了状态,就无法直接更改。相反,只要需要更改,就会创建一个新状态。这种不变性对于维持应用程序的可预测性至关重要,因为它确保每个状态更改都是有意的且可追踪的。

2. 行动:描述发生了什么

Redux 中的操作是描述应用程序中的事件或更改的纯 JavaScript 对象。它们就像传递有关应用程序中发生的情况的信息的信使。每个操作都有一个定义操作性质的类型属性,以及一个可选的有效负载属性,其中包含与该操作相关的任何其他数据。

例如,在待办事项列表应用程序中,操作可能表示添加新的待办事项、完成现有项目或删除项目。每个操作都有一个唯一的类型,例如 ADD_TODO、TOGGLE_TODO 或 DELETE_TODO,并且可能包含其他数据,例如待办事项的 ID 或文本。

操作被分派到存储,并由减速器处理(我们将在接下来讨论)。通过清楚地定义应用程序中发生的情况,操作有助于保持清晰且易于理解的数据更改流。

3.Reducers:定义状态如何改变

Reducer 是 Redux 中的纯函数,定义应用程序的状态应如何响应操作而改变。它们以当前状态和操作作为参数并返回一个新状态。术语“纯函数”意味着reducer的输出仅取决于其输入(当前状态和操作),并且不会产生任何副作用,例如修改外部变量或执行异步操作。

在 Redux 中,reducers 负责实际的状态更新。当分派一个操作时,Redux 将当前状态和操作传递给适当的减速器,然后计算并返回新状态。此过程确保状态以可预测且可追踪的方式发生变化。

例如,待办事项列表应用程序的减速器可能如下所示:

function todoReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, action.payload];
    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.payload.id
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
}

登录后复制

在此示例中,todoReducer 处理两种类型的操作:ADD_TODO 和 TOGGLE_TODO。根据操作类型,它可以向状态添加新的待办事项或切换现有项目的已完成状态。减速器总是返回一个新的状态对象,确保原始状态保持不变。

设置和使用 Redux:详细的分步指南

现在我们已经介绍了 Redux 的核心概念,是时候看看它们如何在现实世界的应用程序中结合在一起了。在本节中,我们将逐步介绍在简单的 React 应用程序中设置和使用 Redux 的过程。

第1步:安装Redux及相关包

使用 Redux 的第一步是安装必要的软件包。 Redux 本身是一个独立的库,但与 React 一起使用时,您还需要安装react-redux,这是一个提供将 Redux 与 React 组件集成的绑定的包。

要安装 Redux 和 React-Redux,请打开终端并在项目目录中运行以下命令:

npm install redux react-redux
登录后复制

此命令会安装 redux 和 react-redux,我们将使用它们将 React 组件连接到 Redux 存储。

第 2 步:创建商店

安装 Redux 后,下一步就是创建存储。存储保存应用程序的状态并提供用于调度操作和订阅状态更改的方法。

在此示例中,我们将为简单的待办事项列表应用程序创建一个商店。首先创建一个处理状态更改的减速器函数:

import { createStore } from 'redux';

// This is our reducer function
function todoReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [...state, action.payload];
    case 'TOGGLE_TODO':
      return state.map(todo =>
        todo.id === action.payload.id
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    default:
      return state;
  }
}

// Create the store
const store = createStore(todoReducer);
登录后复制

在此代码中,todoReducer 函数处理两种类型的操作:ADD_TODO 用于添加新的待办事项,TOGGLE_TODO 用于切换项目的完成状态。 Redux 中的 createStore 函数用于创建存储,并传入 todoReducer 作为参数。

第 3 步:定义操作和操作创建者

动作在 Redux 中至关重要,因为它们描述了应用程序中发生的事情。但是,每次想要分派操作时手动创建操作对象可能会变得很麻烦。这就是动作创建者发挥作用的地方。动作创建者是返回动作对象的函数。

让我们定义一个动作创建器来添加待办事项:

function addTodo(text) {
  return {
    type: 'ADD_TODO',
    payload: { id: Date.now(), text, completed: false }
  };
}
登录后复制

addTodo 函数接受一个文本参数并返回一个类型为 ADD_TODO 的操作对象和包含待办事项数据的有效负载。这个动作创建器简化了分派动作的过程,使代码更具可读性和可维护性。

您还可以定义其他操作创建者,例如toggleTodo,用于切换待办事项的完成状态:

function toggleTodo(id) {
  return {
    type: 'TOGGLE_TODO',
    payload: { id }
  };
}
登录后复制

第 4 步:调度操作以更新状态

存储和操作就位后,您现在可以调度操作来更新状态。分派一个动作是你通知 Redux 应用程序中发生了一些事情,触发适当的减速器来更新状态的方式。

以下是如何调度操作来添加和切换待办事项:

store.dispatch(addTodo('Learn Redux'));
store.dispatch(addTodo('Build an app'));
store.dispatch(toggleTodo(1621234567890));
登录后复制

当您分派 addTodo 操作时,Redux 会使用当前状态和操作调用 todoReducer,并且该缩减器会返回一个包含添加的待办事项项的新状态。同样,当您调度toggleTodo操作时,reducer会更新指定待办事项的完成状态。

第 5 步:访问并订阅状态更改

要读取应用程序的当前状态,可以使用商店提供的 getState 方法。此方法返回存储在 Redux 存储中的整个状态对象:

console.log(store.getState());
// Output: [{ id: 1621234567890, text: 'Learn Redux', completed: true }, 
//          { id: 1621234567891, text: 'Build an app', completed: false }]
登录后复制

除了读取状态之外,还可以使用 subscribe 方法订阅状态变化。此方法允许您在状态更改时执行回调函数,这对于更新 UI 或执行其他副作用以响应状态更新非常有用:

const unsubscribe = store.subscribe(() => {
  console.log('State updated:', store.getState());
});
登录后复制

订阅完状态变化后,可以通过调用 subscribe 返回的函数来取消订阅:

unsubscribe();
登录后复制

第 6 步:将 Redux 连接到 React 组件

要将 Redux 与 React 集成,您需要将 React 组件连接到 Redux 存储。这就是react-redux包发挥作用的地方,它提供了Provider、useSelector和useDispatch实用程序。

首先将整个应用程序包装在 Provider 组件中,并将 Redux 存储作为 prop 传递。这使得 Redux 存储可用于 React 应用程序中的所有组件:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './App';
import todoReducer from './reducers';

// Create the Redux store
const store = createStore(todoReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
登录后复制

接下来,使用 useSelector 和 useDispatch 挂钩将您的组件连接到 Redux 存储。 useSelector 允许您访问状态,而 useDispatch 允许您分派操作:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, toggleTodo } from './actions';

function TodoList() {
  const todos = useSelector(state => state);
  const dispatch = useDispatch();

  const handleAddTodo = (text) => {
    dispatch(addTodo(text));
  };

  const handleToggleTodo = (id) => {
    dispatch(toggleTodo(id));
  };

  return (
    <div>
      <button onClick={() => handleAddTodo('New Todo')}>Add Todo</button>
      <ul>
        {todos.map(todo => (
          <li
            key={todo.id}
            onClick={() => handleToggleTodo(todo.id)}
            style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;
登录后复制

In this example, the TodoList component displays a list of todo items, with the ability to add new items and toggle their completion status. The useSelector hook retrieves the state from the Redux store, while the useDispatch hook allows the component to dispatch actions.

By connecting your React components to Redux in this way, you can ensure that your application's state is managed consistently and predictably.

Best Practices and Common Pitfalls

While Redux is a powerful tool for managing state in complex applications, it also comes with its own set of best practices and potential pitfalls. Understanding these will help you avoid common mistakes and make the most of Redux in your projects.

Best Practices

  • Keep Your State Normalized: In large applications, it's essential to keep your state normalized, meaning that you avoid nesting data too deeply. Instead of storing entire objects within other objects, store only the references (e.g., IDs) and keep the actual objects in a separate, flat structure. This approach simplifies state updates and prevents unnecessary data duplication.
  • Use Action Creators: Action creators are functions that return action objects. They not only make your code more readable but also allow you to modify the structure of actions later without changing the code that dispatches them. Always use action creators instead of directly creating action objects in your components.
  • Use Immutable Update Patterns: Redux relies on immutability, meaning that state objects should never be modified directly. Instead, always return new objects when updating the state in reducers. You can use tools like the spread operator (...) or utility libraries like Immutable.js or Immer to help with this.
  • Keep Reducers Pure: Reducers should be pure functions, meaning that they should only depend on their arguments and not produce side effects, such as modifying external variables or making API calls. This purity ensures that your state changes are predictable and easy to test.
  • Split Your Reducers: As your application grows, so will your state. Instead of having one large reducer that handles everything, split your reducers into smaller, more manageable functions, each responsible for a specific part of the state. Redux provides a combineReducers function to help you merge these smaller reducers into a single root reducer.
  • Use Middleware for Side Effects: Redux is designed to be a synchronous state container, but many applications need to handle asynchronous actions, such as API calls. To manage these side effects, use middleware like redux-thunk or redux-saga, which allows you to handle asynchronous actions in a clean and maintainable way.

Common Pitfalls to Avoid

  • Overusing Redux: Not every piece of state needs to be stored in Redux. While Redux is great for managing application-wide state, it's overkill for local UI state that doesn't need to be shared across components. For example, the state of a dropdown menu or a modal window is better managed with React's built-in useState hook.
  • Mutating State Directly: One of the most common mistakes in Redux is directly mutating the state object in reducers. Doing so can lead to subtle bugs and make your application unpredictable. Always return a new state object instead of modifying the existing one.
  • Putting Everything in One Reducer: While it's possible to manage your entire application's state with a single reducer, doing so will quickly become unmanageable as your application grows. Instead, break down your state into smaller pieces and create a reducer for each piece. Use combineReducers to merge them into a single root reducer.
  • Ignoring the Redux DevTools: Redux DevTools is an invaluable tool for debugging and understanding how your state changes over time. It allows you to inspect every action that is dispatched, view the current state, and even "time travel" by replaying actions. Make sure to integrate Redux DevTools into your development environment.
  • Not Handling Side Effects Properly: Redux is designed to be a synchronous state container, but most applications need to deal with asynchronous actions, such as API calls. If you handle these side effects within reducers or actions, you break the purity of your functions and make your code harder to test and maintain. Instead, use middleware like redux-thunk or redux-saga to manage side effects.

Conclusion and Next Steps

In this comprehensive guide, we've covered the fundamentals of Redux, from its core concepts to setting up and using it in a simple React application. Redux is a powerful tool for managing state in complex applications, but it also comes with its own learning curve and best practices.

通过了解存储、操作和化简器,您可以控制应用程序的状态并确保其行为可预测且一致。通过提供的分步指南,您现在应该能够在自己的项目中设置 Redux 并开始像专业人士一样管理状态。

但是,Redux 是一个广阔的主题,具有许多高级功能和用例。为了加深您的理解,请考虑探索以下内容:

  • 中间件:学习如何使用 redux-thunk 和 redux-saga 等中间件处理异步操作和副作用。
  • Redux Toolkit:使用 Redux Toolkit 简化 Redux 开发,Redux Toolkit 是一组工具和最佳实践,使 Redux 的使用更加轻松、高效。
  • 测试 Redux 应用程序:探索如何为您的减速器、操作和连接的组件编写单元测试。
  • 高级模式:发现高级 Redux 模式,例如处理复杂的状态形状、优化性能以及将 Redux 与其他库集成。
  • 社区和资源:加入 Redux 社区,阅读官方文档,探索在线教程和课程以继续学习。

请记住,掌握 Redux 需要时间和练习。你使用它的次数越多,你就会变得越舒服。不断尝试,不断学习。

以上是了解 Redux:初学者综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!