1、调用 store.dispatch(action)

2、Action 会触发给 Store 指定的 root reducer

3、Store 会保存 root reducer 返回的状态树

四、在 react 中注册使用 redux

1、将 Redux 绑定到 React 实例上

(1)、Provider 组件

(2)、Connect() 方法

一、一句话说 redux

redux 就是:先将需要修改的 state 都存入到 store 里,然后发起一个 action 用来描述发生了什么,然后用 reducers 描述 action 如何改变 state 状态树 ,创建store的时候需要传入reducer,真正能改变 store 中数据的是 store.dispatch API。

二、redux 的成员

1、action

Action 是一个单纯的包含 { type, payload } 的对象,其中:

  • type 是一个常量用来标示动作类型;
  • payload 是这个动作携带的数据。

通常使用函数来生成 action,它最后会返回一个 action 对象。比如:

export function addTodo(text) {
  return {
    type: ActionTypes.ADD_TODO,
    text: text

创建 action 的函数是一个纯函数pure function)——形如 “(state, action) => state一个函数的返回结果只依赖其参数,并且执行过程中没有副作用。

Action 需要通过 store.dispatch() 方法来发送。所以现在要触发一个动作只要调用 dispatchdispatch(addTodo(text))。稍后会讲到如何拿到 store.dispatch。

2、reducer

(1)、组件的 reducer

Reducer 用来处理 Action 触发的对状态树的更改。

所以一个 reducer 函数会接受 oldState 和 action 两个参数,返回一个新的 state:(oldState, action) => newState

const initialState = {
  a: 'a',
  b: 'b'
function someApp(state = initialState, action) {
  switch (action.type) {
    case 'CHANGE_A':
      return { ...state, a: 'Modified a' };
    case 'CHANGE_B':
      return { ...state, b: action.payload };
    default:
      return state
  • 使用 ES6 的扩展语法来确保不会更改到 oldState 而是返回一个 newState。
  • 对于不需要处理的 action,直接返回 oldState

对上述代码用“策略模式”进行优化:

const initialState = {
  a: 'a',
  b: 'b'
function someApp(state = initialState, action) {
  var map = {
    CHANGE_A: function () {
      return { ...state, a: 'Modified a' };
    CHANGE_B: function () {
      return { ...state, b: action.payload };
  if (map[action.type]) {
    return map[action.type]();
  } else {
    return state;

redux 的 Reducer 是一个纯函数,所以绝对不要在 reducer 里面做一些引入 副作用 的事情,比如:

  • 直接修改 state 参数对象
  • 请求 API
  • 调用不纯的函数,比如: Data.now() Math.random()

(2)、根 reducer

Redux 里,一个 Store 对应一个 State 状态,所以整个 State 对象就应该由一个总的 reducer 函数管理。但是,如果所有的状态更改逻辑都放在这一个 reducer 里面,显然会变得巨大而难以维护。得益于纯函数的实现,我们只需要让状态树上的每个字段都有一个自己的 reducer 函数来管理,就可以拆分成很小的 reducer 了:

function someApp(state = {}, action) {
  return {
    a: reducerA(state.a, action),
    b: reducerB(state.b, action)

对于 reducerA 和 reducerB 来说,他们依然是形如:(oldState, action) => newState 的函数。只是这时候的 state 不是整个状态树,而是树上的特定字段,每个 reducer 只需要判断 action,管理自己关心的状态字段数据就好了。

Redux 提供了一个工具函数 combineReducers() 来简化这种 reducer 合并:

import { combineReducers } from 'redux';
const someApp = combineReducers({
  a: reducerA,
  b: reducerB

像 someApp 这种管理整个 State 的 reducer,可以称为根 reducer 即 root reducer。 

3、Store

(1)、创建 store

Store 的作用就是连接 Action 和 Reducer,Store 的具体作用如下:

  • 保持住整个应用的 State 状态树
  • 提供一个 getState() 方法获取 State
  • 提供一个 dispatch() 方法发送 action 更改 State
  • 提供一个 subscribe() 方法注册回调函数监听 State 的更改

创建一个 Store 很容易,将 “root reducer” 函数传递给 createStore() 方法即可:

import { createStore } from 'redux';
import someApp from './reducers';
let store = createStore(someApp);
// 你也可以额外指定一个初始 State(initialState),这对于服务端渲染很有用
// let store = createStore(someApp, window.STATE_FROM_SERVER);

现在我们就拿到了 store.dispatch,可以用来分发 action 了。

(2)、分发 action

// 使用 subscribe 方法创建一个函数,监听 State 的更改
let unsubscribe = store.subscribe(() => console.log(store.getState()));
// 分发 action
store.dispatch({ type: 'CHANGE_A' });
store.dispatch({ type: 'CHANGE_B', payload: 'Modified b' });
// 停止侦听状态更新
unsubscribe();

三、redux 的运作流程

redux 的运作流程如下:store.dispatch(action) -> reducer(state, action) -> store.getState(),这整个过程是一个“单向数据流”。

1、调用 store.dispatch(action)

Action 是一个包含 { type, payload } 的对象,它描述了“发生了什么”,比如:

{ type: 'LIKE_ARTICLE', articleID: 42 }
{ type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } }
{ type: 'ADD_TODO', text: 'Read the Redux docs.' }

你可以在任何地方调用 store.dispatch(action),比如组件内部,Ajax 回调函数里面等等。

2、Action 会触发给 Store 指定的 root reducer

root reducer 会返回一个完整的状态树,State 对象上的各个字段值可以由各自的 reducer 函数处理并返回新的值。

  • reducer 函数接受 (state, action) 两个参数
  • reducer 函数判断 action.type 然后处理对应的 action.payload 数据来更新并返回一个新的 state

3、Store 会保存 root reducer 返回的状态树

新的 State 会替代旧的 State,然后所有 store.subscribe(listener) 注册的回调函数会被调用,在回调函数里面可以通过 store.getState() 拿到新的 State。

这就是 Redux 的运作流程,接下来看如何在 React 里面使用 Redux。

import {createStore} from 'redux';
function count(state = 0, action) {
    switch (action.type) {
        case 'ADD':
            return state + 1
        case 'REDUCER':
            return state - 1;
        default:
            return state
// 创建一个仓库
let store = createStore(count);
let currentValue = store.getState();
console.log('当前的值:', currentValue);
// 定义一个监听的方法
let listener = () => {
    const previosValue = currentValue;
    currentValue = store.getState();
    console.log('上一个值:', previosValue, '当前值:', currentValue)
// 创建一个监听
store.subscribe(listener);
// 分发任务
store.dispatch({type:"ADD"});
store.dispatch({type:"ADD"});
store.dispatch({type:"ADD"});
store.dispatch({type:"REDUCER"});

四、在 react 中注册使用 redux

1、将 Redux 绑定到 React 实例上

react-redux 提供了两个 API:Provider 和 Connect。

(1)、Provider 组件

<Provider> 作为一个容器组件,用来接受 Store,并且让 Store 对子组件可用,用法如下:

import { render } from 'react-dom';
import { Provider } from 'react-redux';
import App from './app';
render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')

这时候 <Provider> 里面的子组件 <App /> 才可以使用 connect 方法关联 store。 

<Provider> 的源码及其实现原理:

import React, { useMemo, useEffect } from 'react'
import PropTypes from 'prop-types'
import { ReactReduxContext } from './Context'
import Subscription from '../utils/Subscription'
function Provider({ store, context, children }) {
  const contextValue = useMemo(() => {
    const subscription = new Subscription(store)
    subscription.onStateChange = subscription.notifyNestedSubs
    return {
      store,
      subscription,
  }, [store])
  const previousState = useMemo(() => store.getState(), [store])
  useEffect(() => {
    const { subscription } = contextValue
    subscription.trySubscribe()
    if (previousState !== store.getState()) {
      subscription.notifyNestedSubs()
    return () => {
      subscription.tryUnsubscribe()
      subscription.onStateChange = null
  }, [contextValue, previousState])
  const Context = context || ReactReduxContext
  return <Context.Provider value={contextValue}>{children}</Context.Provider>
if (process.env.NODE_ENV !== 'production') {
  Provider.propTypes = {
    store: PropTypes.shape({
      subscribe: PropTypes.func.isRequired,
      dispatch: PropTypes.func.isRequired,
      getState: PropTypes.func.isRequired,
    context: PropTypes.object,
    children: PropTypes.any,
export default Provider

Provider 利用了 React 一个(暂时)隐藏的特性 Contexts,Context 用来传递一些父容器的属性对所有子孙组件可见,在某些场景下面避免了用 props 传递多层组件的繁琐。

(2)、Connect() 方法

Connect() 方法用来连接 React 组件与 Redux store,不会改变原来的组件类。

Connect() 方法可以接收 4 个可选的参数:connect([mapStateToProps],  [mapDispatchToProps],  [mergeProps],  [options]):

  • [mapStateToProps(state, [ownProps]): stateProps]:该参数是一个函数,用来管理是否允许组件监听 Redux store 的变化。
    • 第一个可选参数是一个函数,只有指定了这个参数,这个关联(connected)组件才会监听 Redux Store 的更新,每次更新都会调用 mapStateToProps 这个函数,返回一个字面量对象将会合并到组件的 props 属性。
    • 如果你省略了这个 mapStateToProps 参数,你的组件将不会监听 Redux store。
    • ownProps 是可选的第二个参数,它是传递给组件的 props,当组件获取到新的 props 时,ownProps 都会拿到这个值并且执行 mapStateToProps 这个函数。
  • [mapDispatchProps(dispatch, [ownProps]): dispatchProps]:该参数可以是一个对象,也可以是一个函数,用来指定如何传递 dispatch 给组件。
    • 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将action creator的返回值作为参数执行。这些属性会被合并到组件的 props 中。
    • 如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(提示:你也许会用到 Redux 的辅助函数 bindActionCreators())。
    • 如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。
    • ownProps 是可选的第二个参数,它是传递给组件的 props,只要组件接收到新 props,mapDispatchToProps 就会被调用。
  • [mergeProps(stateProps, dispatchProps, ownProps): props]:该参数是一个函数,用来处理 mapStateToProps 和 mapDispatchProps 返回的结果。
    • 如果指定了这个参数,mapStateToProps() 与 mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。
    • 如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。
  • [options]:该参数是一个对象,用来定制 connector 的行为。
    • [pure = true] (Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true。
    • [withRef = false] (Boolean): 如果为 true,connector 会保存一个对被包装组件实例的引用,该引用通过 getWrappedInstance() 方法获得。默认值为 false。

更多 connect() 方法的参数的使用详见官网:https://www.redux.org.cn/docs/react-redux/api.html

Connect() 方法,会返回另一个函数,这个返回的函数用来接受一个组件类作为参数,最后它会返回一个和 Redux store 关联起来的新组件

class App extends Component { ... }
export default connect()(App);

这样就可以在 App 这个组件里面通过 props 拿到 Store 的 dispatch 方法。

本文参考:http://caibaojian.com/react/redux-basic.html

它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk。接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。,将slice中的reducer可以组成一个对象传入此处; ReactDOM.render(VDOM,document.getElementById(‘test’) react: const VDOM=React.createElement(‘h1’,{id:‘title’},‘Hello,React’) ReactDOM.render(VDOM,document.getElementById(‘test’) Redux 是 React 框架下的一款状态管理工具,可以实现多个组件之间的数据共享和传递。学习和掌握 Redux 以及周边生态可以使我们更好的进行 React 项目开发。下面我们就详细的讲述 Redux 在实际项目开发中的使用。 Redux Thunk、Redux Saga等中间件会更复杂一些,它们允许在action中执行异步操作,而不仅仅是在中间件中。这些中间件利用函数包装的方式,允许你在action中编写异步逻辑,然后再dispatch另一个action来更新状态。redux本身是一个同步状态管理库,但他的状态更新过程是通过dispatch一个action来触发的。中间件是Redux的一个扩展机制,他可以在action被dispatch后,到达reducer之前,执行一些额外的逻辑。然而,Redux并不直接支持异步操作。 每每提到Redux都会想起Vuex,相比起Vuex,Redux确实抽象了一些。官方文档给的入门的DEMO中的todoList,其中很多的代码逻辑都得自己去梳理。 容器组件和展示组件 Redux的React绑定库是基于容器组件和展示组件相分离的开发思想。 作用:描述如何展现骨架、样式 直接使用Redux:否 数据来源:props 数据修改:从props调用回调函数 调用... 单一数据源:整个应用中的state被存储在一个store中,即store对象只有一个 state只是可读的:唯一改变state里面值的方式是通过action来触发 使用纯函数来执行修改:reducer是函数,通过执行里面的代码来实现修改 2.redux的基本实现 app.js import React, { Component } from 'react'