React Redux 是 Redux 的官方 React UI 绑定层。它允许您的 React 组件从 Redux 存储读取数据,并将操作分派到存储以更新状态。

# 1、问题剖析

TIP

  经过前面 redux 的学习,我们可以先使用 react 写一个简单的counter 案例(redux 版) (opens new window) 😂

  结果发现:

store 定义时是在正常的、相对便捷的(store 进行了拆分),但在使用 redux 时有大量重复的代码出现

重复代码
// 重复1
import store from './store/index.js'

class Demo extends React.PureComponent {
  constructor() {
    super()

    this.state = {
      // 重复2
      count: store.getState().counter
    }
  }

  componentDidMount() {
    // 重复3
    this.unsubscribe = store.subscribe(() => {
      const state = store.getState()
      this.setState({
        count: state.counter
      })
    })
  }

  // 重复4
  upDownHandle(str) {
    store.dispatch(countChangeAction(str))
  }

  // ……

  componentWillUnMount() {
    // 重复5
    this.unsubscribe()
  }
}

  从本质上讲,产生这种现象的原因时 react 和 redux 之间的关联不够。

# 2、react-redux ✨

  上述问题我们可以使用高阶组件解决,但这些高阶组件不用我们自己封装。

npm install redux react-redux

  redux 官方为了我们在方便在 react 中使用 redux,已经为我们提供了 react-redux (opens new window) 库用于将 react 和 redux 进行关联

我们可以使用其提供的高级组件 :Provider、connect()等达到解耦合、优化使用体验的目的

TIP

  现在,我们可以使用 react-redux 重写一下counter 案例(react-redux 版) (opens new window),以解决在 react 中使用 redux 时发现的部分问题。

# 3、Provider 组件

  Provider 可以为除根组件以外的所有组件提供 store

// index.js
import { Provider } from 'react-redux'
import store from './store'

// ……
root.render(
  // 解决:重复 1
  <Provider store={store}>
    <App />
  </Provider>
)

# 4、connect() 组件

  connect 组件接收两个参数(函数),并返回一个新的高阶组件(函数)

connect 函数 ✍ 实现原理
  • connect.js
import { PureComponent } from 'react'
// import store from '@/store'

export function connect(mapStateToProps, mapDispatchToProps) {
  return function (WrapperComponent) {
    class NewComponent extends PureComponent {
      constructor(props, context) {
        super(props)

        // 🚩(state)
        // this.state = mapStateToProps(store.getState())
        this.state = mapStateToProps(this.context.getState())
      }

      componentDidMount() {
        this.unsubscribe = store.subscribe(() => {
          // this.forceUpdate()
          // this.setState(mapStateToProps(store.getState()))
          this.setState(mapStateToProps(this.context.getState()))
        })
      }

      componentWillUnmount() {
        this.unsubscribe()
      }

      render() {
        // const stateObj = mapStateToProps(store.getState())
        // const dispatchObj = mapDispatchToProps(store.dispatch)
        const stateObj = mapStateToProps(this.context.getState())
        const dispatchObj = mapDispatchToProps(this.context.dispatch) // 🚩(dispatch)

        return <WrapperComponent {...this.props} {...stateObj} {...dispatchObj} />
      }
    }

    // 新增
    NewComponent.contextType = StoreContext

    return NewComponent
  }
}
  • StoreContext.js
import { createContext } from 'react'

export const StoreContext = createContext() // 使用Context传递store
  • index.js
export { StoreContext } from './StoreContext.js'
export { connect } from './connect.js'
  • 使用
// index.js
import { Provider } from 'react-redux'
import store from './store'

import { StoreContext } from 'xxxx'

// ……
root.render(
  <Provider store={store}>
    <StoreContext.Provider value={store}>
      <App />
    </StoreContext.Provider>
  </Provider>
)

  connect() 组件实现:

react 中的 state、dispatch 进行映射(store 代码和 react 代码解耦)

import { connect } from 'react-redux'
import { countChangeAction } from '../store/actionCreators.js'

class Demo extends React.PureComponent {
  //
  upDownHandle(str) {
    // 解决:重复3
    // store.dispatch(countChangeAction(str))
    this.props.countChange(str)
  }

  //
  render() {
    // 解决:重复2
    // store.getState().counter
    const { count } = this.props

    return (
      <div>
        <p>app couter: {count}</p>
        <button onClick={(e) => this.upDownHandle('+1')}>+1</button>
        <button onClick={(e) => this.upDownHandle('+3')}>+3</button>
      </div>
    )
  }
}

// 1、state映射
const mapStateToProps = (state) => ({
  count: state.counter
})

// 2、dispatch映射
const mapDispatchToProps = (dispatch) => ({
  countChange: function (str) {
    dispatch(countChangeAction(str))
  }
})

// connect() 返回的是一个高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(Demo)
更新于 : 7/8/2024, 10:21:14 AM