手写react-redux
当我们使用redux的时候,每次都需要在useEffect中订阅和取消订阅,如果想要更像react, (注意redux只是js状态管理库), 我们可以使用react-redux。
JavaScript
export default function ReactReduxPage(){
const count = useSelector(( { count }) => count);
const dispatch = useDispatch()
const add = useCallback(() => {
dispatch({type: "ADD"})
},[])
return (
<div>
<h1>ReactReduxPage</h1>
<button onClick={add}>{count}</button>
</div>
)
}
JavaScript
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import {Provider} from '../react-redux-nut/Provider'
import {store} from '../store'
createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>,
)
我们发现对比redux(具体可以看juejin.cn/post/753167...)。 我们可以发现
- 用法变得简单了,我们可以使用useSelector,useDispatch获得store的状态和行为。
- 不再需要手动订阅和取消订阅了。
- ReactReduxPage并不需要引入store了,store的来源是Provider传下来的。
这是因为react-redux内部帮我们实现了。
接下来,让我们一步一步来看看react-redux具体怎么实现。
- Provider实现 既然叫Provider,又出现在了顶部组件中,很容易想到react跨组件传递方法: useContext吧。
要知道,分三步走:
(1)创建Context对象 (2)Provider传递value (3)后代消费value
js
export const Context = React.createContext()
export function Provider({store,children}){
return <Context.Provider value={store}>{children}</Context.Provider>
}
-
useSelector和useDispatch
想要去实现这些方法,我们得先看用法,知道我接收什么,返回什么。 useSelector接收一个函数,返回一个状态值。 useDispatch就是返回redux中的store.dispatch。 那么我们就可以实现了。这里没有什么难的
js
export function useSelector(selector){
const store = useContext(Context)
const {getState,subscribe} = store
const selectedState = selector(getState())
return selectedState
}
js
export function useDispatch(){
const store = useContext(Context)
const {dispatch} = store
return dispatch
}
好了,现在我们就实现了一个基本的react-redux,但是此时点击按钮,会发现数字没有改变,因为我们还没有订阅嘛,在使用redux和redux-toolkit也会经常用到这个问题,所以一定要记住,订阅!订阅!订阅!
- react-redux怎么做订阅呢?
使用useSyncExternalStore API,具体的代码可以参考https://www.npmjs.com/package/use-sync-external-store
修改一下useSelector
js
const store = useContext(Context)
const {getState,subscribe} = store
const state = useSyncExternalStore(subscribe,getState)
const selectedState = selector(state)
return selectedState
如果只是react18+
import {useSyncExternalStore} from "react"
如果想兼容旧版本
import {useSyncExternalStore} from "use-sync-external-store/shim"
待完成:手写useSyncExternalStore