react 和 redux 建立通信的方式
有 2 种方案:
老方案 connect 新方案 hook
老方案 connect
曾经, 我们会使用 connect 建立 react 和 redux 的通信, 例如, 在一个 class 写法的组件中:
- import React from 'react'
- import { bindActionCreators } from 'redux'
- import { connect } from 'react-redux'
- import globalAction from 'actions/global'
- @connect(
- // 取得 reducer 中的 state
- state => ({global: state.global}),
- // 取得 action
- dispatch => bindActionCreators({ globalAction }, dispatch)
- )
- class Component extends React.Component {
- componentDidMount() {
- // 从 props 中读取 reducer 和 action
- const {global, globalAction} = this.props
- globalAction()
- console.log(global)
- }
- render() {
- return <p />
- }
- }
对于用习惯了 class 组件的开发者来说, 这种写法烂熟于心了. 但是, 不管你多喜欢这种模式, 还是得学习 react hook.
新方案 hook
随着 react16.8 的发布, hook 功能正式投入使用.
将 react 的 class 组件转换成函数式组件, 想必你已经看过官网的 demo 了, 如果没看, 回头看一下也不晚. 那么, 如果我们使用了 hook, 又该如何跟 redux 通信呢?
针对于这个问题, 业界有人提供了一个取代 react-redux 的新插件 redux-react-hook.
redux-react-hook 使用了 react 提供的 Context(上下文) 功能, 给顶层组件 Provide 传入了 store 对象, 绑定到上下文.
使用了 redux-react-hook 之后, 上面的 demo 就变成了下面这种写法:
- import React, { useEffect } from 'react'
- import { useDispatch, useMappedState, StoreContext } from 'redux-react-hook'
- import globalAction from 'actions/global'
- function Component {
- // 获取上下文的 store 对象
- const store = useContext(StoreContext)
- // 从 store 中读取 reducer
- const {global} = store
- // 从 store 中读取 dispatch
- const dispatch = useDispatch()
- useEffect(() => {
- dispatch(globalAction())
- console.log(global)
- }, [global, dispatch, globalAction])
- render() {
- return <p />
- }
- }
修改后的 demo 使用到了 redux-react-hook 提供的其中 2 个 API,StoreContext 和 useDispatch, 其次, 还可以使用 useMappedState 来获取 reducer 中的状态.
- const mapState = useCallback(
- state => ({
- global: state.global
- }),
- [],
- );
- const { global } = useMappedState(mapState);
- redux-react-hook
简单介绍写 3 个 API,StoreContext,useDispatch,useMappedState.
StoreContext
React 提供的 createContext 创建上下文, 返回该对象.
- import {
- createContext
- } from 'react';
- // 创建 context
- const StoreContext = createContext<TStore | null>(null)
- return StoreContext
- useDispatch
读取 StoreContext, 返回 dispatch.
- function useDispatch(): Dispatch<TAction> {
- // 从上下文读取 store
- const store = useContext(StoreContext);
- if (!store) {
- // store 不存在, 抛出异常
- throw new MissingProviderError();
- }
- return store.dispatch;
- }
- return useDispatch
- useMappedState
useMappedState 跟其他 2 个 API 不太一样, 它是一个自定义的 hook, 用来订阅 reducer 里的状态.
总结
hook 式的写法究竟是好是坏, 暂且无法分辨, 就像有人觉得函数式编程很好, 但有人觉得函数式编程使得代码难于维护.
可以预见的是, 当你使用了 hook, 会在项目中逐渐把 class 消灭, 最后跟 class 语法糖告别, 回归函数的世界.
来源: https://www.2cto.com/kf/201904/805565.html