快照:关于指定数据集合的一个完全可用拷贝,该拷贝包括相应数据在某个时间点(拷贝开始的时间点)的映像。快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。
零、你可能不需要 Redux
需要使用Redux的场景
- 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- view要从多个来源获取数据
多交互、多数据源
从组建的角度
- 某个组建的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组建需要改变全局状态
- 一个组建需要改变另一个组建的状态
==你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化==
一、设计思想
- Web 应用是一个状态机,视图与状态是一一对应的
- 所有的状态,保存在一个对象里面
基本概念和 API
Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
Redux 提供createStore
这个函数,用来生成 Store。
import { createStore } from 'redux';
const store = createStore(fn);
上面代码中,createStore
函数接受另一个函数作为参数,返回新生成的 Store
对象。
State
Store
对象包含所有数据。如果想得到某个时点的数据,就要对Store
生成快照。这种时点的数据集合,就叫做Store
。
当前时刻的 State
,可以通过store.getState()
拿到
import { createStore } from 'redux';
const store = createStore(fn);
const state = store.getState();
一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。
store.subscribe 设置监听函数,一旦state有变化,则自动执行这个函数,触发监听。
一般情况下传入render,一旦state发生变化,则执行render,得到最新的视图。
// store的简单实现
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};
dispatch({});
return { getState, dispatch, subscribe };
};
redux 异步请求
React-Redux 的用法
React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)
UI组件负责UI呈现 容器组件负责管理数据和逻辑
connect() 连接两种组件
connect方法可以省略mapStateToProps参数,那样的话,UI 组件就不会订阅Store,就是说 Store 的更新不会引起 UI 组件的更新
<Provider>组件
提供一个上下文,自组件可以使用store
connect 装饰器写法
对于redux的理解
combineReducers会对传入的reducer进行校验,是否符合规则,会获取每个reducer的初始值,并判断reducer的正确性。
// combineReducers中会调用这个方法
// 获取每个reducer的初始值
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, {
type: ActionTypes.INIT
});
if (typeof initialState === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");
}
if (typeof reducer(undefined, {
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");
}
});
}
最后
// 1、init事件,会返回nextState对象,包含所有reducer的初始值
// 2、每次dispatch的时候,会调用这个函数,循环遍历,判断state是否改变,更新返回的state对象
return function combination(state, action) {
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[_key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
return hasChanged ? nextState : state;
};
}
createStore(rootReducer) 方法注册了几个事件
//createStore function
var currentReducer = reducer;
var currentState = preloadedState;
// 默认会dispatch初始化事件,存下reducer的初始值
dispatch({
type: ActionTypes.INIT
});
return {
dispatch: dispatch,
subscribe: subscribe,
getState: getState,
replaceReducer: replaceReducer
}
// dispatch function
try {
isDispatching = true;
currentState = currentReducer(currentState, action); // 第一次会记录初始值
} finally {
isDispatching = false;
}
每次dispatch回执行combination
遍历reduces,调用所有的reducer,通过返回的nextState与state进行判断,如果不同返回nextState
,相同还是返回之前的state
。最后dispatch获得新的state。