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
  }
}