Redux 的核心: store 是什么?(createStore 函数的实现)

1
const store = createStore(reducer);

store 是一个对象,包含3个方法:getStatedispatchsubscribe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// createStore 函数实现
const createStore = (reducer) => {
let state;
let listeners = [];

const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
}
const subscribe = (listener) => { // listener 就是一个要执行的函数
listeners.push(listener);
return () => { // 采用柯里化方式注销监听器,用法:store.subscribe(listener)();
listeners = listeners.filter(l => l != listener);
}
}

dispatch({}); // 初始化state

return { getState, dispatch, subscribe }
}
  • 由函数可知,当用户 dispatch 一个 action 时,会自动调用 reducer 从而得到最新的 state,该 state 可通过 getState 函数获取,并且会执行所有已注册的函数。

redux 的套路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 定一个 reducer
function reducer (state, action) {
/* 初始化 state 和 switch case */
}

// 生成 store
const store = createStore(reducer)

// 监听数据变化重新渲染页面,即更新状态的过程
store.subscribe(() => renderApp(store.getState()))

// 首次渲染页面
renderApp(store.getState())

// 后面可以随意 dispatch 了,页面自动更新
store.dispatch(...)

React 和 Redux 之间是如何连接?

Store 通过 Provider 传递给了我们的 React 组件,因此,使得组件能够获取到 store。那么它是如何将做到的呢?

React 中父组件 context 的作用,用以摆脱状态提升

  • 在 React 中,父组件使用 getChildContext(),可以将 store 放到它的 context 里面,相当于给子组件设置了一个全局变量,这样每个子组件就都可以获取到 store。

各个函数功能本质

  • State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。

  • store.dispatch()是 View 发出 Action 的唯一方法。

    1
    2
    3
    4
    5
    6
    7
    import { createStore } from 'redux';
    const store = createStore(fn);

    store.dispatch({
    type: 'ADD_TODO',
    payload: 'Learn Redux'
    });
  • 我们说reduers监听某个action,其实就是action可以调用这个reduers函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    const defaultState = 0;
    const reducer = (state = defaultState, action) => {
    switch (action.type) {
    case 'ADD':
    return state + action.payload;
    default:
    return state;
    }
    };


    const actions = [
    { type: 'ADD', payload: 0 },
    { type: 'ADD', payload: 1 },
    { type: 'ADD', payload: 2 }
    ];

    const total = actions.reduce(reducer, 0); // 3
  • 为什么mapStateToProps可以监听state的变换,因为背后调用了store.subscribe,接着调用component.setState

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import { createStore } from 'redux';
    const store = createStore(reducer);

    store.subscribe(listener);

    function listerner() {
    let newState = store.getState();
    component.setState(newState);
    }

各函数执行流程

首先,用户发出 Action。

1
store.dispatch(action);

然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。

1
let nextState = todoApp(previousState, action);

State 一旦有变化,Store 就会调用监听函数。

1
2
// 设置监听函数
store.subscribe(listener);

listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。

1
2
3
4
function listerner() {
let newState = store.getState();
component.setState(newState);
}