一、Provider
Provider 主要的作用就是将外界传入的
store
设置成可以通过 this.context 获取
1. constructor
constructor(props) {
super(props)
// 从外部传入store
const { store } = props
// 根据 store 获取 subscription
this.notifySubscribers = this.notifySubscribers.bind(this)
const subscription = new Subscription(store)
subscription.onStateChange = this.notifySubscribers
// 子组件可以通过 this.context 获取的数据
this.state = {
store,
subscription
}
// 通过 store.getState() 获取到整个应用的 state
this.previousState = store.getState()
}
2. componentDidMount
componentDidMount() {
this._isMounted = true
// 添加订阅
this.state.subscription.trySubscribe()
// 如果整个应用的 state 发生变化,则执行订阅
if (this.previousState !== this.props.store.getState()) {
this.state.subscription.notifyNestedSubs()
}
}
3. componentWillUnmount
// 移除订阅
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe()
this.state.subscription.tryUnsubscribe()
this._isMounted = false
}
4. componentDidUpdate
// 更新store 和 subscription
componentDidUpdate(prevProps) {
if (this.props.store !== prevProps.store) {
this.state.subscription.tryUnsubscribe()
const subscription = new Subscription(this.props.store)
subscription.onStateChange = this.notifySubscribers
this.setState({ store: this.props.store, subscription })
}
}
5. notifySubscribers
notifySubscribers() {
this.state.subscription.notifyNestedSubs()
}
6. render
render() {
// ReactReduxContext 是通过 React.createContext(null) 创建的context对象
// 通过 Context.Provider 包裹的children组件都可以通过context获取到 value 中的值
const Context = this.props.context || ReactReduxContext
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
二、Connect
连接 React 组件与 Redux
store
,最终会返回一个包着渲染组件的高阶组件
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]);
connect 接受四个参数:
mapStateToProps
,mapDispatchToProps
,mergeProps
,optipons
,返回一个注入了 state 和 action creator 的 React 组件使用事例:
const mapStateToProps = (state) => ({
reducers: state.todo,
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(actions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
1. mapStateToProps
mapStateToProps(state, ownProps) : stateProps
,将store
中的数据 state 作为 props 绑定到组件上
第一个参数
state
就是 store 存储的整个应用的 state第二个参数
ownProps
是组件自己的 props,可不传当
state
变化,或者ownProps
变化的时候,mapStateToProps
都会被调用,计算出一个新的stateProps
(在与 ownProps merge 后)更新给组件
2. mapDispatchToProps
mapDispatchToProps(dispatch, ownProps): dispatchProps
,将action
作为 props 绑定到组件上
- 通过
bindActionCreators
将actions
和dispatch
组合起来生成 mapDispatchToProps 需要生成的内容
bindActionCreators.js
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(this, arguments));
};
}
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch);
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${
actionCreators === null ? 'null' : typeof actionCreators
}. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
);
}
const keys = Object.keys(actionCreators);
const boundActionCreators = {};
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const actionCreator = actionCreators[key];
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
}
return boundActionCreators;
}
3. mergeProps
不管是 stateProps
还是 dispatchProps
,都需要和 ownProps
merge 之后才会被赋给组件。connect 的第三个参数就是用来做这件事。通常情况下,可以不传这个参数,connect 就会使用 Object.assign 替代该方法
4. connectAdvanced
三、Subscription
1. 核心 API
使用到的核心 API 主要有三个
notifyNestedSubs
trySubscribe
tryUnsubscribe
1.1 notifyNestedSubs
执行 listener
notifyNestedSubs() {
this.listeners.notify()
}
1.2 trySubscribe
创建订阅函数
trySubscribe() {
if (!this.unsubscribe) {
// 通过 store.subscribe 获取订阅函数,该订阅函数在store.dispatch(action)时,会被调用
this.unsubscribe = this.parentSub
? this.parentSub.addNestedSub(this.handleChangeWrapper)
: this.store.subscribe(this.handleChangeWrapper)
// 创建订阅高阶函数 listeners
this.listeners = createListenerCollection()
}
}
1.3 tryUnsubscribe
取消订阅,清空 listeners
tryUnsubscribe() {
if (this.unsubscribe) {
this.unsubscribe()
this.unsubscribe = null
this.listeners.clear()
this.listeners = nullListeners
}
}
2. createListenerCollection
创建 listeners 的高阶函数,主要提供四个方法
clear()
notify()
get()
subscribe(listener)
源代码及注解如下:
const CLEARED = null;
const nullListeners = { notify() {} };
// 创建 listeners 的高阶函数
function createListenerCollection() {
// batch 就是执行参数中的回调函数
const batch = getBatch();
// the current/next pattern is copied from redux's createStore code.
let current = [];
let next = [];
return {
// 清空 next 和 current 中的 listener
clear() {
next = CLEARED;
current = CLEARED;
},
// 执行 listener
notify() {
// 将 next 赋值给 current,遍历执行 current 中的 listener
const listeners = (current = next);
batch(() => {
for (let i = 0; i < listeners.length; i++) {
listeners[i]();
}
});
},
// 获取 next
get() {
return next;
},
// 订阅 listener
subscribe(listener) {
let isSubscribed = true;
// 复制 current 给 next,仅对 next 进行 push 操作
if (next === current) next = current.slice();
// 添加 listener 至 next 中
next.push(listener);
// 返回取消订阅的函数
return function unsubscribe() {
if (!isSubscribed || current === CLEARED) return;
isSubscribed = false;
// 复制 current 给 next,仅对 next 进行 splice 操作
if (next === current) next = current.slice();
// 移除 listener
next.splice(next.indexOf(listener), 1);
};
},
};
}