Redux實(shí)現(xiàn)見(jiàn)如下地址。
http://www.itdecent.cn/p/41499425c475
react-redux可以幫助redux更好的在react中使用
主要提供Provider,useSelector、useDispatch和connect方法
Provider實(shí)現(xiàn)
依賴React的context讓全局可訪問(wèn)store
const context = React.createContext()
function Provider({ store, children }) {
return <context.Provider value={store}>{children}</context.Provider>
}
useSelector和useDispatch實(shí)現(xiàn)
//一個(gè)強(qiáng)制組件更新的自定義hooks
function useForceUpdate() {
const [, setState] = useReducer((x) => x + 1, 0);
const update = useCallback(() => {
setState()
}, [])
return update
}
function useSelector(mapState) {
const store = useContext(context)
const update = useForceUpdate()
//它會(huì)在所有的 DOM 變更之后同步調(diào)用 effect??梢允褂盟鼇?lái)讀取 DOM 布局并同步觸發(fā)重渲染。
//在瀏覽器執(zhí)行繪制之前,useLayoutEffect 內(nèi)部的更新計(jì)劃將被同步刷新。
useLayoutEffect(() => {
const unsubscribe = store.subscribe(() => {
update()
})
return () => {
unsubscribe()
}
}, [store])
return mapState(store.getState())
}
function useDispatch() {
const store = useContext(context)
return store.dispatch
}
connect實(shí)現(xiàn)
function connect(mapState, mapDispatch) {
// 返回一個(gè)高階組件函數(shù)
return function (WrappedComponent) {
//返回組件
return function (props) {
const store = useContext(context)
const stateProps = mapState(store.getState())
let dispatchProps = { dispatch: store.dispatch }
// mapDispatch為對(duì)象的格式如下
// {
// parapmsChange: (prams) => ({ type: prams })
// }
if (typeof mapDispatch === 'object') {
let obj = {}
Object.keys(mapDispatch).forEach(item => {
obj[item] = function (parapm) {
store.dispatch(mapDispatch[item](parapm))
}
})
dispatchProps = obj
} else if (typeof mapDispatch === 'function') {
dispatchProps = mapDispatch(store.dispatch)
}
const update = useForceUpdate()
useLayoutEffect(() => {
const unsubscribe = store.subscribe(() => {
update()
})
return () => {
unsubscribe()
}
}, [store])
return <WrappedComponent {...props} {...stateProps} {...dispatchProps} />;
}
}
}
測(cè)試代碼
import { createStore } from './redux'
const reducer = function (state = { count: 1 }, action) {
switch (action.type) {
case 'increase':
state.count += 1
return JSON.parse(JSON.stringify(state))
case 'decrease':
state.count -= 1
return JSON.parse(JSON.stringify(state))
default:
return JSON.parse(JSON.stringify(state))
}
}
export default createStore(reducer)
import store from './store/index'
import { Provider } from './react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
import React from 'react';
import { connect, useDispatch, useSelector } from './react-redux'
class ClassComp extends React.Component {
render() {
const { count, parapmsChange } = this.props
return <div >
<button onClick={() => parapmsChange('increase')}>parapmsChange+</button>
ClassComp {count}
<button onClick={() => parapmsChange('decrease')}>parapmsChange-</button>
</div>
}
}
const NewClassComp = connect(state => ({ count: state.count }),
{ parapmsChange: (prams) => ({ type: prams }) })(ClassComp)
function FnComp() {
const count = useSelector(state => state.count)
const dispatch = useDispatch();
return <div>
<button onClick={() => dispatch({ type: 'increase' })}>+</button>
FnComp {count}
<button onClick={() => dispatch({ type: 'decrease' })}>-</button>
</div>
}
function App() {
return (
<div className="App">
<NewClassComp />
<FnComp />
</div>
);
}