24、Redux 应用架构全解析

Redux 应用架构全解析

1. 认识 Redux:Flux 的变体

Redux 是实现 Flux 思想的一个广泛使用且知名的库,它以一种略有修改的方式实现了 Flux 的理念。Redux 被其文档描述为“JavaScript 应用的可预测状态容器”,具体来说,它以自己的方式实践了 Flux 的概念。

与 Flux 相比,Redux 有以下重要区别:
| 对比项 | Flux | Redux |
| ---- | ---- | ---- |
| 存储方式 | 应用中状态信息可位于多个存储中 | 使用单一全局存储 |
| 状态修改 | 无特定的更具不可变性的修改方式 | 引入了 reducers,以可预测和确定性的方式一次修改一部分状态,且仅在全局存储中进行 |
| 中间件 | 无 | 引入中间件,可在数据更新时注入自定义行为 |
| 动作与存储的关系 | 无明确的解耦描述 | 动作创建者不直接向存储分发任何内容,而是返回供中央调度器使用的动作对象 |

Redux 架构主要由动作(actions)、存储(store)和 reducers 组成。它使用一个单一的集中式状态对象,通过特定的、确定性的方式进行更新。当需要更新状态时(通常是由于点击等事件)会创建一个动作,该动作有一个特定的类型,由某个 reducer 处理。处理该动作类型的 reducer 会复制当前状态,用动作中的数据进行修改,然后返回新状态。当存储更新时,视图层(如 React)可以监听更新并相应地做出响应。

2. 为 Redux 做好准备

Redux 既是一种应用架构范式,也是一个可以安装的库。与“原生”的 Flux 实现相比,Redux 具有明显优势。Flux 范式有众多实现,如 Flummox、Fluxxor 等,它们的社区支持程度和 API 各不相同。而 Redux 拥有强大的社区支持,其库本身的 API 小巧而强大,成为 React 应用架构中最受欢迎和依赖的库之一。

要开始使用 Redux,需要完成以下操作:
1. 确保使用当前章节的源代码运行 npm install ,以在本地安装所有正确的依赖项。在本章中,将开始使用一些新库,如 js-cookie redux-mock-store redux
2. 安装 Redux 开发者工具。可以使用它们在浏览器中检查 Redux 存储和动作。Redux 设计上具有可预测性,这使得创建强大的调试工具变得容易。Redux Dev Tools 扩展可以让你跟踪应用状态的单个更改、检查更改之间的差异,甚至可以随时间倒回和重放应用状态。要为你的浏览器安装它,请遵循 https://github.com/zalmoxisus/redux-devtools-extension 上的说明。

3. 在 Redux 中创建动作

在 Redux 中,动作是将数据从应用发送到存储的信息有效负载。除了动作,存储没有其他获取数据的方式。动作在整个 Redux 应用中用于发起数据更改,但它们本身并不负责更新应用的状态(存储),reducers 在这方面更为关键。

一个 Redux 动作是一个普通的 JavaScript 对象(POJO),必须有一个 type 键,还可以包含其他所需信息。以下是一些简单的动作示例:

{
    type: 'UPDATE_USER_PROFILE',    
    payload: { 
        email: 'hello@ifelse.io'    
    }
}
{
    type: 'LOADING'     
}
{
    type: 'appName/dashboard/insights/load'  
}
3.1 定义动作类型

可以通过定义一些动作类型,开始将应用过渡到 Redux 架构。这些动作类型通常对应于用户操作,如登录、注销、更改表单值等,但也可以是与网络请求相关的操作,不一定是用户直接触发的。

在小型应用中,可能不需要在常量文件中定义动作类型,可以在创建动作时直接传递或硬编码。但随着应用的增长,跟踪动作类型会变得困难,可能导致调试或重构问题。因此,通常建议定义动作类型。

以下是一些示例动作类型的定义,将其放在 src/constants/types.js 文件中:

export const app = {                                                    
    ERROR: 'letters-social/app/error',
    LOADED: 'letters-social/app/loaded',
    LOADING: 'letters-social/app/loading'
};
export const auth = {
    LOGIN_SUCCESS: 'letters-social/auth/login/success',
    LOGOUT_SUCCESS: 'letters-social/auth/logout/success'
};
export const posts = {
    CREATE: 'letters-social/post/create',
    GET: 'letters-social/post/get',
    LIKE: 'letters-social/post/like',
    NEXT: 'letters-social/post/paginate/next',
    UNLIKE: 'letters-social/post/unlike',
    UPDATE_LINKS: 'letters-social/post/paginate/update'
};
export const comments = {
    CREATE: 'letters-social/comments/create',
    GET: 'letters-social/comments/get',
    SHOW: 'letters-social/comments/show',
    TOGGLE: 'letters-social/comments/toggle'
};
3.2 创建 Redux 动作

定义了动作类型后,就可以开始创建动作了。动作通过动作创建者(返回动作对象的函数)创建,并由存储使用调度函数进行分发。

以下是创建加载和加载完成动作的动作创建者示例,将其放在 src/actions/loading.js 文件中:

import * as types from '../constants/types';    
export function loading() { 
  return {
    type: types.app.LOADING      
  };
}
export function loaded() {      
  return {
    type: types.app.LOADED
  };
}
3.3 创建 Redux 存储并分发动作

动作创建者本身不会改变应用状态,需要使用 Redux 提供的调度器才能使动作创建者生效。调度函数由 Redux 存储提供,是将动作发送到 Redux 进行处理的方式。

在设置存储之前,需要创建一个根 reducer 文件。在 src 中创建一个名为 reducers 的文件夹,并在其中创建一个 root.js 文件。使用 Redux 提供的 combineReducers 函数将多个 reducers 组合成一个:

import { combineReducers } from 'redux';   
const rootReducer = combineReducers({});      
export default rootReducer;   

接下来,配置和设置存储。创建一个名为 store 的文件夹,并在其中创建几个文件: store.js stores/store.prod.js stores/store.dev.js 。这些文件负责导出一个为你创建存储的函数,并在开发模式下集成开发者工具。

src/store/configureStore.js 文件:

import { __PRODUCTION__ } from 'environs';              
import prodStore from './configureStore.prod'; 
import devStore from './configureStore.dev';
export default __PRODUCTION__ ? prodStore : devStore;   

src/store/configureStore.prod.js 文件:

import { createStore } from 'redux';
import rootReducer from '../reducers/root';
let store;
export default function configureStore(initialState) {    
  if (store) {
    return store; 
  }
  store = createStore(rootReducer, initialState);   
  return store;
}

src/store/configureStore.dev.js 文件:

import thunk from 'redux-thunk';
import { createStore, compose} from 'redux';   
import rootReducer from '../reducers/root';
let store;
export default initialState => {
    if (store) {                     
        return store;
    }
    const createdStore = createStore(
        rootReducer,
        initialState,
        compose(window.devToolsExtension())    
    );
    store = createdStore;
    return store;
};

Redux 存储暴露了两个重要函数: getState dispatch getState 用于在给定时间点获取 Redux 存储状态的快照, dispatch 用于将动作发送到 Redux 存储。以下是使用之前设置的加载动作创建者通过存储分发几个动作的示例,放在 src/store/exampleUse.js 文件中:

import configureStore from './configureStore';        
import { loading, loaded } from '../actions/loading';
const store = configureStore();
console.log('========== Example store ===========');
store.dispatch(loading());                       
store.dispatch(loaded());          
store.dispatch(loading());
store.dispatch(loaded());
console.log('========== end example store ===========');

通过以上步骤,你可以逐步搭建起一个基于 Redux 的应用架构,利用其可预测性和强大的状态管理能力来构建更稳定、易于调试的应用。

4. Redux 工作流程总结

为了更清晰地理解 Redux 的工作流程,我们可以通过一个 mermaid 流程图来展示:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([事件触发]):::startend --> B(动作创建者):::process
    B --> C(动作对象):::process
    C --> D(调度器):::process
    D --> E(存储):::process
    E --> F{是否有匹配的 Reducer?}:::decision
    F -->|是| G(匹配的 Reducer):::process
    F -->|否| H(无操作):::process
    G --> I(生成新状态):::process
    I --> E(存储):::process
    E --> J(视图层更新):::process

这个流程图展示了 Redux 中从事件触发到视图层更新的完整流程:
1. 事件触发 :用户的操作(如点击按钮)或其他事件触发动作创建者。
2. 动作创建者 :生成动作对象,包含 type 和可能的 payload
3. 调度器 :将动作对象发送到存储。
4. 存储 :接收动作对象,并查找匹配的 Reducer。
5. Reducer :如果找到匹配的 Reducer,它会根据动作对象的信息生成新的状态。
6. 视图层更新 :存储状态更新后,视图层(如 React 组件)监听变化并更新显示。

5. Redux 的优势与应用场景
5.1 Redux 的优势
  • 可预测性 :Redux 的设计使得状态的变化是可预测的,所有的状态变化都通过动作和 Reducer 进行,便于调试和维护。
  • 易于调试 :借助 Redux 开发者工具,可以跟踪状态的变化、查看动作历史记录,甚至可以回退和重放状态变化。
  • 可扩展性 :通过中间件和组合 Reducer 的方式,Redux 可以轻松应对复杂的应用场景,便于应用的扩展。
5.2 应用场景
  • 大型应用 :当应用规模较大,状态管理变得复杂时,Redux 可以帮助组织和管理状态,提高代码的可维护性。
  • 多人协作开发 :Redux 的规范和可预测性使得多人协作开发时,团队成员更容易理解和维护代码。
  • 需要时间旅行调试的场景 :在开发过程中,如果需要对状态变化进行调试和回溯,Redux 开发者工具可以提供很大的帮助。
6. 常见问题及解决方案

在使用 Redux 的过程中,可能会遇到一些常见问题,以下是一些问题及对应的解决方案:

问题 解决方案
动作类型管理困难 使用常量文件统一管理动作类型,避免硬编码,提高代码的可维护性。
性能问题 合理使用中间件,避免不必要的状态更新,使用 shouldComponentUpdate 等方法优化组件渲染。
状态更新不及时 确保动作创建者和 Reducer 的逻辑正确,检查中间件是否影响了状态更新。
7. 总结与展望

通过本文的介绍,我们了解了 Redux 的基本概念、与 Flux 的区别、动作的创建、存储的配置以及工作流程等内容。Redux 作为一种强大的状态管理库,在现代前端开发中发挥着重要的作用。

在未来的开发中,我们可以进一步探索 Redux 的高级特性,如异步操作、中间件的使用等,以应对更复杂的应用场景。同时,结合其他前端框架和库,如 React、Vue 等,可以构建出更加高效、稳定的应用。

希望本文能够帮助你更好地理解和使用 Redux,在实际项目中发挥其优势,提升开发效率和应用质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值