React:快速上手(5)——掌握Redux(2)

React:快速上手(5)——掌握Redux(2)

本文部分内容参考阮一峰的Redux教程

React-Redux原理

React-Redux运行机制

  我觉得这张图清楚地描述React-Redux的运行机制:

  React-Redux将组件划分为两类,第一类是UI组件:

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

  比如,我们的实例计数器就是一个UI组件,我们只写了UI的呈现规则,并且所有数据都是由this.props提供:

class Counter extends React.Component{
    render() {
        const{onSubmitClick,value}  = this.props;
        return(
            <div>
                <span>{value}</span>
                <button onClick={onSubmitClick}>提交</button>
            </div>
        )
    }
}

  第二类组件是容器组件:

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

  不过,React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成

 

Connect负责从UI组件生成容器组件

  如下,一行语句,我们就将获得由UI组件得到的容器组件

const CounterApp = connect(mapStateToProps,mapDispatchToProps)(Counter)

  这个函数由两个参数,mapStateToProps和mapDispatchToProps构成。它们主要定义业务逻辑,前者负责输入逻辑,即容器组件如何将state转换为props交给UI组件,来供容器组件进行UI渲染后者负责输出逻辑,用来建立 UI 组件的参数到store.dispatch方法的映射

  如下,我们定义mapStateToProps,它将state中的count字段取出映射到value属性,然后交给UI组件:

function mapStateToProps(state) {
    return{
        value:state.count
    }
}

  然后,我们定义mapDispatchToProps,他将store.dispatch方法映射到onSubmitClick属性上,这样UI组件通过props.onSubmitClick,就可以间接调用store.dispatch,实现状态更新。

function mapDispatchToProps(dispatch) {
    return{
        onSubmitClick:()=>dispatch({type:'INCREASE'})
    }
}

<Provider>组件

  connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。

  React-Redux 提供Provider组件,可以让容器组件拿到state

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp);

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

 上面代码中,Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了。

一个完整的计数器例子

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'

// React component
class Counter extends Component {
  render() {
    const { value, onIncreaseClick } = this.props
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>
    )
  }
}

Counter.propTypes = {
  value: PropTypes.number.isRequired,
  onIncreaseClick: PropTypes.func.isRequired
}

// Action
const increaseAction = { type: 'increase' }

// Reducer
function counter(state = { count: 0 }, action) {
  const count = state.count
  switch (action.type) {
    case 'increase':
      return { count: count + 1 }
    default:
      return state
  }
}

// Store
const store = createStore(counter)

// Map Redux state to component props
function mapStateToProps(state) {
  return {
    value: state.count
  }
}

// Map Redux actions to component props
function mapDispatchToProps(dispatch) {
  return {
    onIncreaseClick: () => dispatch(increaseAction)
  }
}

// Connected Component
const App = connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

  

posted @ 2019-01-24 14:37  子烁爱学习  阅读(285)  评论(0编辑  收藏  举报