理解原理的关键点:
1、createStore 函数返回 getState,subscribe,dispatch三个参数。
2、subscribe负责收集connect内部的更新方法forceComponentUpdateDispatch,并设置进去lisenters。
3、key就是这里
4、观察函数变化 bindActionCreators函数变化
4.1:传递两个函数进去bindActionCreator,然后把其中一个函数放在另一个函数里面执行,这有点难理解,因为日常写法很少这么写的。
4.2:将 (…args) => dispatch(actionCreator(…args)); 转化成 (…args) => dispatch({ type: ‘ADD’ });
4.3:然后在bindActionCreator里面返回 { add: (…args) => dispatch({ type: ‘ADD’ }) }
context.js
下面展示一些 内联代码片
。
import React, { Component, useLayoutEffect, useReducer, useContext } from 'react'
export const ReactReduxContext = React.createContext();
App.js
import Home from './component/home'
import React, { Component } from 'react';
import {ReactReduxContext} from './component/context';
import store from './component/redux';
class App extends Component {
render() {
return ( <div>
<ReactReduxContext.Provider value={store}>
<Home />
</ReactReduxContext.Provider>
</div> );
}
}
export default App;
redux.js
import React, { Component, useLayoutEffect, useReducer, useContext } from 'react'
import {ReactReduxContext} from './context';
// ------------------------------------------------------------------------------
export const connect = (mapStateToProps = (state) => state, mapDispatchToProps) =>
(WrappedComponent) => (props) => {
const store = useContext(ReactReduxContext);
const { getState, dispatch, subscribe } = store;
console.log('store1', store)
console.log('getState', getState)
// mapStateToProps 是在使用 connect 时传入的第一个参数,
// getState 获取到 state 到值,然后传递给 mapStateToProps 使用
// mapStateToProps 执行完成后返回需要传递给组件的 stateProps
const stateProps = mapStateToProps(getState());
// connect 的第二个参数 mapDispatchToProps 可以是对象或者函数
let dispatchProps;
if (typeof mapDispatchToProps === 'object') {
// 如果 mapDispatchToProps 是一个对象,则使用 bindActionCreators 将该对象包装成可以直接调用的函数对象
dispatchProps = bindActionCreators(mapDispatchToProps, dispatch);
} else if (typeof mapDispatchToProps === 'function') {
// 如果 mapDispatchToProps 是一个函数,则调用函数并传入 dispatch
dispatchProps = mapDispatchToProps(dispatch);
} else {
// 默认传递 dispatch
dispatchProps = { dispatch };
}
function storeStateUpdatesReducer(state, action) {
return state + 1;
}
// 使用 useReducer 实现强制更新页面
// useReducer 返回的数组包含两个项 state, dispatch],调用 dispatch 返回新的 state 时,组件会重新渲染
const [state, forceComponentUpdateDispatch] = useReducer(
storeStateUpdatesReducer,
0
);
useLayoutEffect(() => {
// 订阅 store 中数据更新,强制刷新页面
const ubsubscribe = subscribe(() => {
forceComponentUpdateDispatch();
});
return () => {
// 卸载组件取消订阅
ubsubscribe && ubsubscribe();
};
}, [store]);
// 将需要“连接”的组件返回,并传递给组件需要的数据
return <WrappedComponent {...props} {...stateProps} {...dispatchProps} />;
};
// ------------------------------------------------------------------------------
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args));
}
function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
const boundActionCreators = {};
for (let key in actionCreators) {
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
}
return boundActionCreators;
}
// ------------------------------------------------------------------------------
function createStore(reducer) {
let currentState;
let lisenters = [];
function getState() {
return currentState;
}
function subscribe(listener) {
lisenters.push(listener);
// return function unsubscribe() {
// const index = lisenters.indexOf(lisenter);
// lisenters.splice(index, 1);
// };
}
function dispatch(action) {
// 调用 reducer 函数,修改当前的 state
currentState = reducer(currentState, action)
// 循环调用回调函数
for (let i = 0; i < lisenters.length; i++) {
const lisenter = lisenters[i];
lisenter()
}
}
return {
getState,
subscribe,
dispatch,
}
}
const reducer = (state = 0, action) => {
console.log('调用到reducer');
switch (action.type) {
case 'ADD':
return state + 1;
case 'MINUS':
return state - 1;
default:
return state;
}
};
const store = createStore(reducer);
export default store;
home.js
import React, { Component } from 'react';
import { connect } from './redux';
class Home extends Component {
add = () => {
this.props.dispatch({ type: 'ADD' });
};
minus = () => {
this.props.dispatch({ type: 'MINUS' });
};
asyncAdd = () => {
this.props.dispatch((dispatch) => {
setTimeout(() => {
dispatch({ type: 'ADD' });
}, 1000);
});
};
render() {
return (
<div>
<div>count: {this.props.count}</div>
{/* <button onClick={this.add}>add</button> */}
<button onClick={this.props.add}>add</button>
<button onClick={this.minus}>minus</button>
<button onClick={this.asyncAdd}>asyncAdd</button>
</div>
);
}
}
const mapStateToProps = (state) => ({ count: state });
const mapDispatchToProps = {
add: () => ({ type: 'ADD' }),
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);