这一节美容不是很难次要是react-reudx的外围局部,这部分其实redux也有,就是Provider、connect、bindActionCreators等几个罕用的API的实现。
间接上外围代码
import React, { useLayoutEffect, useReducer, useCallback, useContext } from 'react';
const useForceUpdata = () => {
const [_, forceUpdata] = useReducer(x => x + 1, 0,);
const upDate = useCallback(() => forceUpdata(), [])
return upDate
};
const Cunsumer = ({ store }, mapStateToProps, mapDispatchToProps, WarppedComponent, props) => {
// stateProps其实就是以所有state为参数,mapStateProps执行的后果
const forceUpdata = useForceUpdata()
const stateProps = mapStateToProps(store.getStore());
// dispatchProps须要麻烦一点因为会有两种状况
// 第一种mapDispatchProps是函数
// 第二种mapDispatchProps是对象
let dispatchProps = { dispatch: store.dispacth };
// 这里补充一下最精确的判断数据类型的办法:Object.prototype.toString.call(mapDispatchProps)
if (typeof mapDispatchToProps === "function") {
dispatchProps = mapDispatchToProps(store.dispach)
}
else if (typeof mapDispatchToProps === "object") {
dispatchProps = bindActionCreators(mapDispatchToProps, store.dispach)
}
// * 重点 这里是必须要写订阅的不然咱们代码跑起来不会报错然而页面也不会刷新,
// * redux 只是一个状态存储库,不具备主动刷新页面的性能,须要咱们自行编写订阅代码
// * 这里应用useLayoutEffect而不是useEffect,是因为useLayoutEffect在dom变更后就开始同步执行,而useEffect有提早
useLayoutEffect(() => {
const unsubscribe = store.subscribe(() => {
forceUpdata()
})
return () => {
unsubscribe()
};
}, [store])
return <WarppedComponent {...props} {...stateProps} {...dispatchProps} />
};
// 创立Context
const Context = React.createContext();
// 导出Provider组件
export const Provider = ({ store, children }) => {
return <Context.Provider value={store}>{children}</Context.Provider>
};
export const connect = ({ mapStateToProps, mapDispatchToProps }) => WarppedComponent => props => {
// 子孙组件生产父级传下来的value
return <Context.Cunsumer>
{(value) => Cunsumer(value, mapStateToProps, mapDispatchToProps, WarppedComponent, props)}
</Context.Cunsumer>
}
export const bindActionCreators = (data, dispacth) => {
let obj = {}
for (const key in data) {
obj[key] = dispacth((...arg) => obj[key](...arg))
}
return obj
};
export const useDispatch = () => {
const store = useContext(Context)
// 间接返回store中的dispatch即可
return store.dispatch
}
export const useSelector = (selctor) => {
const store = useContext(Context)
// 这里一样是要订阅一下不然页面不会更新
useLayoutEffect(() => {
const unsubscribe = store.subscribe(() => {
forceUpdata()
})
return () => unsubscribe()
}, [store])
return selctor(store.getStore())
}
以上便是几个罕用API的根本实现.
重点说一下
- 咱们这里写的useSelector不能够反复调用, 不然会产生反复订阅的成果,影响性能。
- 订阅时应用useLayoutEffect而不是useEffect,是因为useLayoutEffect在dom变更后就开始同步执行,而useEffect有提早,详情请移步
发表回复