• [React]React-Redux用法


    来源:
    Redux入门教程-阮一峰
    Redux中文文档

    React-Redux是Redux对于React的封装

    UI组件

    React-Redux将所有的组件分为两大类,UI组件和容器组件。
    UI组件将不带有任何逻辑,无状态,所有的参数由this.props提供且不使用Redux的API
    例如:

    const Title=
        value=><h1>{value}</h1>;
    

    UI组件不含有状态,因此也被称为纯组件,与纯函数相同,也由参数决定其值。

    容器组件

    容器组件负责管理数据和状态,不呈现UI,且使用Redux's API

    在大多数情况下要将组件进行拆分,使其由外面包裹的容器组件和内部的UI组件构成。外部的容器组件负责与外部的通信,将数据传给UI组件,UI组件负责渲染出视图。
    React-Redux规定,所有的UI组件都由用户提供,容器组件是由React-Redux自动生成的。

    connect()

    React-Redux提供connect()方法,用于从UI组件生成容器组件。

    import {connect} from 'react-redux'
    const VisibleTodoList=connect()(TodoList);
    

    上面的代码将UI组件TodoList通过connect()生成VisibleTodoList容器组件。

    需要为了容器组件定义业务逻辑:

    • 输入逻辑:外部的数据转换为UI组件的参数
    • 输出逻辑:用户的动作变为Action对象,从UI组件传出。

    connect的完整API如下:

    import {connect} from 'react-redux'
    
    const VisibleTodoList=connect(
        mapStateToProps,
        mapDispatchToProps
    )(TodoList)
    

    在上面的代码中,connect()接收了两个参数:mapStateToprops和mapDispatchToProps。它们定义了UI组件的业务逻辑。

    mapStateToProps()

    mapStateToProps是一个函数。它的作用是建立一个从外部state对象到UI组件的props对象的映射关系。
    它执行后返回一个对象,里面的一个键值对就是一个映射。

    const mapStateToProps=(state)=>{
        return{
            todos:getVisibleTodos(state.todos,state.visibilityFilter)
    }
    }
    

    在上面的代码中,mapStateToProps函数接收了state作为参数,返回一个对象。这个对象有一个todos属性,代表UI组件的同名函数,后面的getVisibleTodos也是一个函数,将会从state种获得todos的值。
    例如:

    const getVisibleTodos = (todos, filter) => {
      switch (filter) {
        case 'SHOW_ALL':
          return todos
        case 'SHOW_COMPLETED':
          return todos.filter(t => t.completed)
        case 'SHOW_ACTIVE':
          return todos.filter(t => !t.completed)
        default:
          throw new Error('Unknown filter: ' + filter)
      }
    }
    

    mapStateToProps会订阅store,在state更新的时候就会自动地执行,重新计算UI组件的参数从而触发UI组件的重新渲染。
    mapStateToProps的第一个参数是state对象,第二个参数代表容器组件的props对象。
    在使用第二个参数之后,如果容器组件的参数发生变化,将会引发UI组件重新渲染。

    connect方法可以忽略mapStateToProps参数,这时Store的更新不会引起UI组件的更新。

    mapDispatchToProps()

    mapDispatchToProps()是connect()函数的第二个参数,用来建立UI组件的参数到store.dispatch()方法的映射。它定义了哪些用户的操作应该作为Action传给Store进行处理。
    它可以是函数或者对象。
    如果它是函数,它的入参为dispatch和ownProps(容器组件的props对象)两个参数。

    const mapDispatchToProps = (
      dispatch,
      ownProps
    ) => {
      return {
        onClick: () => {
          dispatch({
            type: 'SET_VISIBILITY_FILTER',
            filter: ownProps.filter
          });
        }
      };
    }
    

    mapDispatchToProps作为函数返回了一个对象,该对象的每个键值对定义了UI组件的参数如何发出Action。

    mapDispatchToProps是一个对象时,它的每个键名是对应的UI组件的同名参数,键值为一个函数(Action creator),返回的Action将会由Redux自动发出。

    const mapDispatchToProps = {
      onClick: (filter) => {
        type: 'SET_VISIBILITY_FILTER',
        filter: filter
      };
    }
    

    组件

    connect()方法生成容器组件后,需要使容器组件得到state才能生成UI组件的参数。

    为了避免一级级地传递state导致的不必要的麻烦,使用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')
    

    在上面的例子中,App组件的所有子组件默认可以得到state。
    原理是React组件的context机制。

    计数器实例

    地址

    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--UI组件
    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')
    )
    

    另一个例子

    将之前提过的面包屑实例进行完善:
    在这个例子中,需要在切换路由的时候,将state中的当前菜单名字状态赋给面包屑UI组件的props,进一步重新渲染UI;
    在切换路由的子组件中,需要在路由变化时发送Action改变Store;

    import {switchMenu} from './../../redux/action'
    import {connect} from 'react-redux'
    //...
    
    class Navleft extends React.Component{
        //...
        handleOnClick=({item}){
            const {dispatch}=this.props;
            //产生Action改变Store
            dispatch(switchMenu(item.props.title));
        }
        render(){
            return (
                //...
                <Menu 
                    onClick={this.handleOnClick}
                    
                        {...}
                    </Menu>
    );
    }
    }
    //连接
    export default connect()(Navleft);
    

    以上的代码在路由菜单切换时产生Action改变Store。
    接下来要在Store改变时重新渲染面包屑UI

    import {connect} from 'react-redux'
    class Header extends React.Component{
       render() {
            return (
                //...
            );
        }
    }
    //connect参数,通过state影响props
    const mapStateToProps=state=>{
        return{
            menuName:state.menuName
        }
    }
    //连接
    export default connect(mapStateToProps)(Header)
    

    在以上的例子中,在UI组件中通过{this.props.menuName}就可以获得在容器组件中的状态。
    这样就达到了在切换菜单时改变面包屑显示的目的。

  • 相关阅读:
    Webservice学习之新建一个最简单的Webservice项目
    初学程序一定要养成良好的习惯
    你晚上睡好了吗?
    如何面对失恋?
    多病之秋少言多饮
    转:避开秋季相冲食物
    转:饭后九不要包你保健康
    转:五官不适预示五脏衰弱
    转:过度疲劳的27个信号与预防方法
    foxmail是不是不行了?
  • 原文地址:https://www.cnblogs.com/liuju/p/12650287.html
Copyright © 2020-2023  润新知