React-Redux
May 25, 2022
build you own react-redux
我们会在顶层存放我们的数据,然后通过 context 传递给各个组件,对于顶层的数据,为了避免被随意更改,我们会使用 redux 保护起来。
// index.ts
import { Provider } from 'react-redux'
// createStore 与 reducer 都来自前文实现的 redux
const store = createStore(reducer)
<Provider store={store}>
<App />
</Provider>
// App.tsx
import { connect } from 'react-redux'
export function InnerApp(props) {
const onChange = (e) => {
props.actions.updateName(e.target.value)
}
return (
<div>
<h1>name: {props.value.name}</h1>
<h2>age: {props.value.age}</h2>
<input type="text" onChange={onChange} />
</div>
)
}
const App = connect(
(state) => {
return {
value: state
}
},
(dispatch) => ({
updateName: (name) => {
dispatch({
type: 'UPDATE_NAME',
payload: name
})
}
})
)(InnerApp)
export default App
以上是 react-redux 使用的一个简单的例子,我们需要实现的就是 Provider 与 connect。Provider 负责将普通的对象转化为 redux 的 store 对象并通过 context 传递给各个组件
export const Provider: FC<Props> = (props) => {
const store = createStore(reducer)
// 将 redux 数据通过 context 传递
return (
<ReactReduxContext.Provider value={store}>
{props.children}
</ReactReduxContext.Provider>
)
}
connect 负责将 store 对象中的数据与操作 store 对象的方法传递给需要的组件。其实不需要 connect 组件也是可以通过 context 的方法拿到 store 的数据,但是这样这个组件就依赖 context 来获取数据,如果别人需要使用这个组件但是他却提供不了这个 context,那就没法使用了。因此我们可以将 context 的获取与实际实现的组件分开,实际的组件 所以你可以实现一个通用的组件,有稳定的 props,然后通过 connect 来将其与 context 连接起来,对于组件来说,他并不关心你的数据获取方式,你只要给到我这坨数据就可以了
export const connect: FC = (
mapToStateFromProps,
mapToActionFromProps
) {
return ( WarpComponent ) => {
const Connect: FC = (ownProps) => {
const store = useReactReduxContext()
const [allProps, setAllProps] = useState()
const updateProps = (newState) => {
const stateProps = mapToStateFromProps(newState, ownProps)
const actionProps = mapToActionFromProps(store.dispatch, ownProps)
setAllProps({ ...stateProps, ...actionProps, ...ownProps })
}
useEffect(() => {
updateProps(store.getState())
const sub = store.subscribe((state) => {
updateProps(state)
})
return () => sub.unsubscribe()
}, [])
return <WarpComponent { ...allProps } />
}
return Connect
}
}