Redux 完整指南

2025-06-11

Redux 完整指南

各位程序员们大家好!今天我们将讨论使用 React 和 Redux 构建真正复杂的应用程序所需了解的一些概念。

在本文中,我们将详细介绍以下概念:

  • 为什么我们需要 redux?
  • 什么是 Redux?
  • 创建 React-redux 应用程序的步骤
    • 步骤 1:创建用户组件
    • 第 2 步:创建商店
    • 步骤3:创建 Reducer
    • 步骤 4:与组件共享 Redux Store
    • 步骤 5:使用 Redux Thunk 添加异步函数中间件
    • 步骤 6:构建 Action Creator
    • 步骤 7:将 Redux Store 连接到组件

开始吧!!🚀🚀

为什么选择 Redux?

在我们了解 Redux 的更多细节之前,首先尝试理解为什么我们真正需要它?

在一个具有许多组件的复杂应用程序中,如果您想在多个组件之间共享状态,那么您可以想到的一种方法就是使用props

图像.png

但是props并不能完全解决我们的问题,因为它只能让你使用自上而下的方式将数据从父组件发送到子组件,而不能反过来。这意味着子组件中发生的任何状态变化都不会影响父组件的状态。

另外, props未能解决的另一个问题是在没有父子层次结构的组件之间共享状态。

因此,为了克服上述所有问题并实现跨组件状态同步,Redux应运而生。通过这种方式,我们将所有状态存储在全局,所有其他组件都可以访问。

Redux是一个用于管理应用程序状态的开源 JavaScript 库。

图像.png

什么是 Redux?

  • Redux 主要用于状态管理。
  • 它可以与所有 javascript 框架和库一起使用,例如 React、angular 等。

Redux 的主要元素包括:

  • Store:如果你正在开发一个大型应用程序,状态会从 React 组件中分离出来,放到它自己的store中。store 是存储当前状态的全局组件,它是一个不可变的对象。
  • 动作:商店中的状态不会直接改变,而是通过不同的动作来改变。
  • Reducer:用于定义动作对应用程序状态的影响。
  • 订阅:用于创建商店状态改变时调用的回调函数。

Redux 原则:

  • 应用程序的全局状态作为对象存储在单个存储库中。
  • 改变状态的唯一方法就是采取dispatch行动。
  • 使用纯减速器函数进行更改。

图像.png

让我们通过一个简单的例子来详细探讨每一个:

我们将遵循以下文件夹结构:

📦src
 ┣ 📂actions
 ┃ ┣ 📜types.js
 ┃ ┗ 📜users.js
 ┣ 📂components
 ┃ ┗ 📂Users
 ┃ ┃ ┣ 📜index.js
 ┃ ┃ ┗ 📜user.css
 ┣ 📂reducers
 ┃ ┣ 📜index.js
 ┃ ┗ 📜users.js
 ┣ 📂store
 ┃ ┗ 📜index.js
 ┣ 📜App.js
 ┗ 📜index.js
Enter fullscreen mode Exit fullscreen mode

你可以在我的github repo中找到最终代码

现在我们将创建一个使用 REST API 获取用户数据并使用 Redux 显示它的应用程序。

最后,我们的应用程序将如下所示:

GifMaker_20210531023908270.gif

创建一个 React 应用程序并使用安装 redux npm install react-redux --save

步骤 1:创建用户组件

src/components/Users/index.js文件中:

import React, { useEffect, useState } from 'react';
import './user.css';

export default function Users() {

    const [userDetails, setUserDetails] = useState([]);

    const handleButtonClick = () => {
        // make a call to Action Creator
    }

    return (
        <div className="container">

            <button className="btn" value="click me" onClick={handleButtonClick}>
                 Fetch Data
            </button>

            <table>
                <tbody>
                    <tr>
                        <th>Id</th>
                        <th>Name</th>
                        <th>Phone</th>
                        <th>Email</th>
                        <th>Website</th>
                    </tr>
                    {
                        userDetails && userDetails.map((item, key) => {
                            return (
                                <tr>
                                    <td>{item.id}</td>
                                    <td>{item.name}</td>
                                    <td>{item.phone}</td>
                                    <td>{item.email}</td>
                                    <td>{item.website}</td>
                                </tr>
                            )
                        })
                    }
                </tbody>
            </table>
        </div>
    )
}

Enter fullscreen mode Exit fullscreen mode

在上面的代码中,每当用户单击按钮时,我们都会进行 API 调用以使用 REST API 获取数据并以表格格式显示数据。

但在进行 API 调用之前,让我们先设置我们的商店

第 2 步:创建商店

我们将在文件中创建一个Redux 存储src/store/index.js

import { createStore } from "redux";
import rootReducer from "../reducers";

const preloadedState = {};

const store = createStore(
    rootReducer,
    preloadedState 
);

export default store;
Enter fullscreen mode Exit fullscreen mode
  • Redux 核心库有一个createStore API,可以创建存储。
  • 我们将传递下一步中创建的rootReducer作为参数。
  • createStore还可以接受preloadedState值作为其第二个参数。您可以使用它在创建 store 时添加初始数据。

要记住的要点:

  • 该商店基本上汇集了构成您的应用程序的stateactions和。reducers
  • Redux 应用程序中只能有一个存储。
  • 每个 Redux 存储都有一个根 reducer 函数。

步骤3:创建 Reducer

  • Reducers 基本上告诉我们如何根据执行的操作更新状态
  • 它必须是纯函数并且不应产生任何副作用。
  • 它必须由不可变的对象组成。如果状态发生变化,旧对象不会被改变,而是被一个新的、改变的对象所取代。

让我们创建我们的reducer src/reducers/user.js

import { USER_DETAILS } from '../actions/types';

const initialState = {
  userDetails: {}
}

export default function (state = initialState, action) {

  console.log("Step 4: Inside User Reducer after action creator dispatches an action");
  switch (action.type) {
    case USER_DETAILS:
      return {
        ...state,
        userDetails: action.payload,
      };
    default:
      return state;
  }
}
Enter fullscreen mode Exit fullscreen mode

它是一个函数,以当前状态和动作作为参数,返回一个新状态。

现在我们已经创建了一个减速器,但是随着我们的应用程序变得越来越复杂,我们可能需要引入更多的减速器。

因此在这种情况下,我们将创建主根Reducer,它将结合我们应用程序中使用的所有其他 Reducer。

src/reducers/index.js文件中:

import { combineReducers } from "redux";
import userReducer from "./users";

export default combineReducers({
    userReducer: userReducer,
   //other reducers
});

Enter fullscreen mode Exit fullscreen mode

我们可以通过使用combineReducers函数组合两个或多个现有的reducer来为我们的应用程序创建实际的reducer

合并式Reducer 的工作方式是,每个action都会在合并后的 Reducer 的各个部分中得到处理。通常情况下,只有一个 Reducer 会对某个 action 感兴趣,但有时多个 Reducer 会根据同一个 action 更改各自的状态部分。

步骤 4:与组件共享 Redux Store

由于我们已经初步创建了我们的商店,下一步是使其可供我们应用程序中的所有组件使用。

src/App.js文件中:

import React from 'react';
import store from './store';
import { Provider } from 'react-redux';
import Users from './components/Users';

function App() {
  return (
    <Provider store={store}>
      <Users/>
      </Provider>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

通过这种方式,所有组件都可以访问商店。

步骤 5:使用 Redux Thunk 添加异步函数中间件

设置好商店后,现在我们需要进行 API 调用来获取数据,但在此之前,我们将向商店添加中间件,以便我们创建异步操作。

Redux Thunk

这个库就是所谓的redux-middleware,它必须随着store的初始化一起初始化。

因此,可以定义action-creators,以便它们返回以redux-store 的dispatch方法作为参数的函数。

因此,我们可以创建异步动作创建器,它首先等待某些操作完成,然后再分派真正的动作。

要将 redux-thunk 引入我们的应用程序,首先使用安装它npm install --save redux-thunk

现在在src/store/index.js文件中:

import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "../reducers";

const preloadedState = {};

const middleware = [thunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
    rootReducer,
    preloadedState,
    composeEnhancers(
        applyMiddleware(...middleware)
    )
);

export default store;
Enter fullscreen mode Exit fullscreen mode

正如你所注意到的,我们在上面的代码中引入了许多新术语。让我们尝试逐一探索它们。

撰写

compose 是高阶函数的一个例子。它接受一组函数作为参数,并返回一个由所有这些函数组成的新函数。

  • 当您想要将多个商店增强器传递给商店时使用它。
  • 它从右到左组合单参数函数。最右边的函数可以接受多个参数,因为它为生成的复合函数提供了签名。例如:compose(f, g, h)与 doing 相同(...args) => f(g(h(...args)))

商店增强剂

  • 它们是高阶函数,为 store 添加了一些额外的功能。Redux 默认提供的唯一 store 增强器是applyMiddleware

应用中间件

  • 创建一个 store 增强器,将中间件应用于Redux store 的dispatch方法。这对于各种任务都很方便,例如以简洁的方式表达异步操作或记录每个操作的有效负载。
  • 因为中间件可能是异步的,所以这应该是组合链中的第一个存储增强器。

我们将在下一步中看到调度的用法。

步骤 6:构建 Action Creator

现在是时候创建一个使用 REST API 获取数据的动作创建器了。

动作创建者是一个创建动作的纯函数。

动作是普通的 JS 对象,它有一个type字段,可以包含额外的数据。它会创建一个事件来描述应用程序中发生的事情。

我们将type在单独的文件中声明所有字段src/actions/types.js

export const USER_DETAILS = 'USER_DETAILS';
Enter fullscreen mode Exit fullscreen mode

构建 Action 创建器:-

src/actions/user.js文件中:

import axios from "axios";
import { USER_DETAILS } from './types';

export const getUserDetails = () => async (dispatch) => {

    console.log("Step 2: Inside Action Creator to make an API call");
    const res = await axios.get('https://jsonplaceholder.typicode.com/users');

    console.log("Step 3: Dispatch an Action to update the state");
    dispatch({
        type: USER_DETAILS,
        payload: res
    })
}
Enter fullscreen mode Exit fullscreen mode

在上面的代码片段中,我们进行了 API 调用,一旦我们得到响应,我们就分派动作,以便我们可以改变状态。

商店现在使用reducer来处理操作,这些操作通过其调度方法调度或“发送”到商店

步骤 7:将 Redux Store 连接到组件

我们终于完成了商店的设置。只差一步,请继续关注🤓🤓。

src/components/Users/index.js文件中:

import React, { useEffect, useState } from 'react';
import { getUserDetails } from '../../actions/users';
import { connect } from "react-redux";
import './user.css';

function Users({ getUserDetails, userReducer }) {

    const [userDetails, setUserDetails] = useState([]);

    const handleButtonClick = () => {

        //make a call to the Action creator
        console.log("Step 1: Make a call to Action-creator from Users Component");
        getUserDetails();
    }

    useEffect(() => {

        // Update the UI as soon as we get our response through API call
        console.log("Step 5: Inside UseEffect of User Component to update the UI")
        setUserDetails(userReducer.userDetails.data);
    }, [userReducer.userDetails])

    return (
        <div className="container">
          .....
        </div>
    )
}

const mapStateToProps = (state) => ({
    userReducer: state.userReducer
});

const mapDispatchToProps = {
    getUserDetails
}

export default connect(mapStateToProps, mapDispatchToProps)(Users);

Enter fullscreen mode Exit fullscreen mode

在上面的代码片段中,我们借助 与组件共享 redux 存储connect

高阶组件是一个接受“常规”组件作为参数并返回一个新的“常规”组件作为返回值的函数。

连接

  • react-redux 提供的connect方法是高阶组件的一个例子。

  • connect方法用于转换“常规” React 组件,以便 Redux 存储的状态可以“映射”到组件的 props 中。

  • 它接受两个参数:mapStateToPropsmapDispatchToProps

mapStateToProps

它是一个函数,可用于定义基于 Redux 存储状态的连接组件的 props。

mapDispatchToProps

  • 它是动作创建器函数的 JS 对象,作为道具传递给连接的组件。
  • mapDispatchToProps中传递的函数必须是动作创建者,即返回 Redux 动作的函数。

正如您所注意到的,我们如何将动作创建者redux 状态作为参数传递给用户组件。

点击按钮时,我们会调用 action-creator 进行 API 调用并更新 redux 状态。
我们useEffect将监控 redux 状态的变化,并使用响应数据更新 UI。

终于,我们基于 Redux 的 React 应用准备好了!!!😎😎

react-redux.gif

我们可以使用Redux Devtools来测试和调试 Redux 状态如何变化。

图像.png

你可以在我的github repo中找到最终代码

包起来!!

感谢您的时间!让我们一起学习,共同成长。

LinkedIn Twitter Instagram

请我喝杯咖啡

鏂囩珷鏉ユ簮锛�https://dev.to/anuradha9712/a-complete-guide-to-redux-hmj
PREV
使用 Prometheus 监控 API 健康检查
NEXT
1-10 个 TypeScript 项目的自定义实用程序类型