Redux 知识点梳理和实践

1,340 阅读4分钟

之前在有道云笔记上写过一篇 Redux 学习实践的文章,附带了一个小 Demo。由于一段时间没看 Redux,加上之前缺乏足够的练习,现在想重构个人博客,使用 Redux 进行状态。现在不得不回头再看看 Redux 相关东西。这里顺便记录下学习笔记,一来便于回顾,二来希望对他人有所帮助。笔记同步写在个人博客网站

这篇文章是知识点的梳理,如果你对 Redux 的基础有一定了解,阅读起来可能比较合适。

什么是 Redux?

Redux 可以说是 Flux 架构思想的最佳实践方案,用于对大型、复杂、多数据来源的 React 进行数据管理。遵循 Redux 的设计原则,再配合 React 容器组件、展示组件分离的代码组织原则,可以让我们的项目结构清晰,数据流清晰,十分利于项目的维护开发。

Redux 设计的三大原则

  1. 单一的数据来源,所有的数据保存在一个对象中。
  2. 状态只读,Reducer 根据 store dispatch 的 action 类型返回一个新的状态,不修改原来的状态。
  3. 状态修改均由纯函数完成。

关于这三大原则的深入理解建议参考 《深入React技术栈》、《深入浅出React和Redux》

浅谈 Redux 的工作过程(和 MVC 的主要区别)

有 MVC 框架使用经验的同学应该清楚,MVC 的工作过程是这样:view 层将用户行为传递到 controller 中的action, controller 中的 action 和 Model 层交互操作数据,返回到 view。通常 MVC 框架的实现 M 和 V 层是可以交互的,这样数据就不是单向流动,这种设计很多场景下很灵活,写起来很爽快,但是要项目过大,项目数据流复杂,项目维护就不爽了。

Redux 则严格遵循上面提到的设计三大原则,工作过程是这样的:view 层触发一个 action,这个 action 由 store.dispatch(action) 传递给 reducer,reducer 根据 previousState 和 action type 返回一个新的 state(不修改数据), 如此实现了数据的变更。

Redux 核心 API

上面 Redux 的工作过程提到了 Redux 有 store、action、reducer 这些概念,这些都是 Redux 对外提供的核心 API,我们来看看他们分别是干嘛的。

  1. store

    store 作为整个应用数据的唯一来源,用于保存数据和 dispatch action。store 使用 Redux 提供的 createStore 方法来生成。

    import { createStore } from 'redux';
    let store = createStore(reducer)
    

    createStore 接受一个 reducer 作为参数,返回一个 store 对象。store 对象包含 4 中方法:

    getState():// 用于获取 store 中当前的状态
    dispatch():// 用于分发 action,这个是改变 store 中数据的唯一方式
    subscribe(listener):// 注册一个监听者,在 store 发生变化时被调用
    replaceReducer(nextReducer):///更新当前 store 中的 reducer
    
  2. reducer

    reducer 本质上是一个函数,这个函数能接受一个 action 和一个旧的状态(previousState),根据 previousState 和 action 返回新的状态

    reducer(previousState, action) => newState
    

reducer 必须是一个纯函数,不能修改原来状态,关于纯函数的概念请阅读其他资料学习。

  1. action

    reducer 的 action 本质上是一个 javaScript 对象,这个对象必须有一个 type 属性,用来表明 action 的类型,还可以有 payload, error, meta 属性。关于 action 对象的属性,社区有个规范,可以参考github.com/redux-utili…

    const action = {
        type: 'ADD_TODO',
        payload: 'todo'
    }
    

    reducer 就是根据 action type 属性来决定返回新的 state。

先睹为快

我在学习 Redux 的时候,看了很多文档,认为对 Redux 的概念了然于胸,但是动手写第一个小 Demo 的时候仍然觉得很难下手,可能是 Redux 这些概念对我而言太新。这里给出我写的第一个小 Demo。

这个 Demo 实现了点击按钮让数字加一减一的功能,没有任何复杂度,单纯的是为了了解 actionstorereducer 的具体作用和协作关系。

Demo 地址: github.com/wewin11235/…

为了便于观察,Demo 的代码都丢在了一个文件里,在实际开发中,一定要遵循好的代码组织原则。

import React from 'react';
import ReactDOM from 'react-dom';

// 创建 action
// action 是 javaScript 对象,是用户行为的抽象,必须包含一个 stype 字段
// 根据 Demo 需要实现记数功能,抽象出两种 action, 一种表示加,一种表示减
const incream_action = { type: 'INCREAM' };
const decream_action = { type: 'DECREME' };

// 创建 reducer
// reducer 接受一个 previousState 和 action 返回一个新的 state
const reducer = (state=0, action) => {
  switch (action.type) {
    case incream_action.type:
      return state + 1;
    case decream_action.type:
      return state - 1;
    default:
      console.log('default');
      return state;
  }
}

// 创建 store
// store 创建使用 createStore(reducers)
// createStore 由 redux 提供
import { createStore } from 'redux';
let store = createStore(reducer);

// 创建计数组件
class Counter extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { count, doIncrement, doDecrement } = this.props
    return(
      <div>
        <span>{count}</span>
        <button onClick={doIncrement}>+</button>
        <button onClick={doDecrement}>-</button>
      </div>
    )
  }
}

const render = () => ReactDOM.render(
  <Counter
    count={store.getState()}
    doIncrement={() => store.dispatch(incream_action)}
    doDecrement={() => store.dispatch(decream_action)}
  />,
  document.getElementById('root')
);

render();

// 为了能在 store 发生变化后能刷新页面,需要给 store 注册一个监听事件
// store 变化后,刷新页面
store.subscribe(render);

最小 Redux 应用诞生。

欢迎指正,补充!