React-redux学习总结

说明

本篇文章是根据React-redux中文文档学习之总结,若有不恰当之处,忘加以斧正;

前篇

上一篇中我已经介绍来Redux的一些知识概念已经总结经验,地址: Redux个人学习总结 , 这篇文章主要是讲如何在React中使用redux,redux生态中提供了Reduct-redux解决方案。

介绍

React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据

安装

  npm install --save react-redux

或者

  yarn add react-redux

使用方法:略

核心概念(Provider 和 connect)

Provider:

使Redux store可用于connect()调用下面组件层次结构中。通常,如果没有<Provider>包装父级或祖先组件,则无法使用connect()。<Provider/>使得每一个被connect()函数包装过的嵌套组件都可以访问到Redux store。

props:

  • store(Redux Store):你应用里的唯一Redux store
  • children(ReactElement):根组件

demo

import React from "react";
import ReactDOM from "react-dom";

import { Provider } from "react-redux";
import store from "./store";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

connect(重点,做好笔记):

connect函数的主要作用是将一个React组件连接到Redux Store。

  connect()(MyComponent);
  // 与下面语句等价
  connect(
    null,
    null
  )(MyComponent);

connect参数(着重将前2个);

  • mapStateToProps?: Function(常用)
  • mapDispatchToProps?: Function | Object(常用)
  • mergeProps?: Function (具体用法参考:网址
  • options?: Object (具体用法参考网址
 function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)

1. 使用使用mapStateToProps抽取数据

参数:

  1. state
  2. ownProps(可选)
mapStateToProps?: (state, ownProps?) => Object

详解:
mapStateToProps可以传递2个参数,第二个参数是可选的;

  • state:如果指定了第一个参数,那么新组件就会向Redux store订阅更新。这意味着任何时候store一旦更新,mapStateToProps就会被调用。mapStateToProps的结果必须是一个纯对象,之后该对象会合并到组件的props;如果你不希望订阅store(就是不监听store中state的更新),可以将此参数设置为null或undefined;
// TodoList.js 

//  在组件中可是使用props调用: 如 props.todoList


// 简写,这种方法也可以定义mapStateToProps函数
/**
* const mapStateToProps = (state) =>{
*    const { todos } = state;
*    return { todoList: todos.allIds };
*  }
*/


function mapStateToProps(state) {
  const { todos } = state;
  return { todoList: todos.allIds };
};
    
export default connect(mapStateToProps)(TodoList);

  • ownProps(可选参数) 如果组件需要用自身的props数据以从store中检索出数据,你可以传入第二个参数,简单一点理解就是:定义了这个属性可以把组件定义的属性传递进来;
  // Todo.js

  function mapStateToProps(state, ownProps) {
    const { visibilityFilter } = state;
    const { id } = ownProps;
    const todo = getTodoById(state, id);
  
    // 组件额外接收:
    return { todo, visibilityFilter };
  };
  
  // 之后,在你的应用里,渲染一个如下父组件:
  <ConnectedTodo id={123} />
  // 你的组件接收 props.id, props.todo, 以及 props.visibilityFilter

返回值:

mapStateToProps方法应该返回一个包含了组件用到的数据的纯对象:每一个对象中的字段都将作为你组件的一个prop字段中的值用来判断你的组件是否需要重新渲染;

注意事项

  • mapStateToProps方法应该足够快;一旦store改变了,那么他的状态就会改变,如果太耗时、容易成为性能瓶颈;
  • mapStateToProps方法应该纯净且同步;尽量不要再这里做异步操作;
  • 使用Selector方法去抽取和转化数据;如果需要根据state生成新的对象返回给组件使用;(就是通过外部方法进行数据处理)
  • 恰当的使用ownProps参数;当有(state,ownProps)两个参数时,每当store state不同、或每当包装props变化时,函数都会运行。
  • 考虑使用Redux的中间件Reselect,替代state替代数据变化(Reselect这个中间件要解决的问题是:在组件交互操作的时候,state发生变化的时候如何减少渲染的压力.在Reselect中间中使用了缓存机制,链接Reselect

2. 使用使用mapStateToProps抽取数据

  mapDispatchToProps?: Object | (dispatch, ownProps?) => Object

注意:mapDispatchToProps作为connect的第二个参数,他可以是一个对象,也可以是一个函数或者为null

  • mapDispatchToProps为null时候或者connect的第二个值为空时;

      // 或者
      connect(mapStateToProps /** 没有第二个参数 */)(MyComponent);
    

    一旦你以这种方式连接了你的组件,你的组件就会接收props.dispatch。你可以用它来向store中分发actions。

      function Counter({ count, dispatch }) {
        return (
          <div>
            <button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
            <span>{count}</span>
            <button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
            <button onClick={() => dispatch({ type: "RESET" })}>reset</button>
          </div>
        );
      }
    
  • 当mapDispatchToProps传递的是一个对象:其内部的每一个函数都被假定为一个Redux action 创建函数,这个对象会作为props传递给连接组件,且其内部每个字段名都与action creators相同,但被一个能调用dispatch方法的函数包装,这样一来这些分发函数就可以直接调用。

    案例

    
    import * as React from 'react'
    
    // 导入 action函数;
    import { addTodo, deleteTodo, toggleTodo } from './actionCreators'
    
    
    
    //组件可以通过props.addTodo 调用
    
    class TodoApp extends React.component{
      ... // 代码部分省略
      ;<button onClick={() => this.props.addTodo()} />
      ...
    }
    
    const mapDispatchToProps = {
      addTodo,
      deleteTodo,
      toggleTodo
    }
    
    export default connect(
      null,
      mapDispatchToProps
    )(TodoApp)
    
  • 如果mapDispatchToProps传递是一个函数时候,该函数会有2个参数;
    参数

    • dispatch: Function
    • ownProps?: Object
    • [1] 函数第一个参数就是dispatch,我们可以使用dispatch去绑定action创建函数;

      案例

      class TodoApp extends React.component{
       ... // 代码部分省略
       const {increment,decrement,reset} = this.props; 
       // 调用
       ;<button onClick={increment} />
       ;<button onClick={decrement} />
       ;<button onClick={reset(1)} />
       
       ...
      }
      
      
      // 定义 mapDispatchToProps函数,第一个参数为dispatch
      const mapDispatchToProps = dispatch => {
         return {
           // dispatching plain actions
           increment: () => dispatch({ type: 'INCREMENT' }),
           decrement: () => dispatch({ type: 'DECREMENT' }),
           reset: (id:number) => dispatch({ type: id })
         }
       }
      
    • [2] 函数的第二个参数是ownProps,第二个参数就是传递给连接组件的props,同样,当对应connect绑定的组件上的值发送改变时候,mapDispatchToProps通过浅比较判断是否需要重新运行(在使用的时候需要判断是否需要此参数、否则容易多次运算)

      案例

      
      // 导入
      import { toggleTodo } from './action';
      
      // 被外部组件引用组件
      ;<TodoApp todoId={123} />
      
      
      //todoApp.ts
      
      ;<button onClick={() => this.props.toggleTodo(this.props.todoId)} />
      
      // 绑定 “props” 变化
      const mapDispatchToProps = (dispatch, ownProps) => {
        toggleTodo: () => dispatch(toggleTodo(ownProps.todoId))
      }
      
      export default connect(null, mapDispatchToProps)(TodoApp)
      
  • 如果不提供mapDispatchToProps函数,置空就行

返回值:

mapDispatchToProps函数返回一个纯对象。
  • 每一个对象的字段都会作为你的组件的一个独立prop,并且字段的值通常是一个调用后能分发action的函数。
  • 如果你在dispatch()中使用了action创建函数(区别于纯对象形式的action),通常约定字段名与action创建函数的名称相同

2.1 如果在用mapDispatchToProps参数的时候,Redux提供了一个函数(bindActionCreators)简化这个操作:

bindActionCreators将值为action creators的对象,转化为同键名的新对象,但将每个action creators封装到一个dispatch调用中,以便可以直接调用它们

bindActionCreators接收两个参数:

  • 一个函数(action creator)或一个对象(每个属性为一个action creator)
  • dispatch
  
  import { bindActionCreators } from "redux";

  const increment = () => ({ type: "INCREMENT" });
  const decrement = () => ({ type: "DECREMENT" });
  const reset = () => ({ type: "RESET" });
  
  // 绑定一个action creator
  // 返回 (...args) => dispatch(increment(...args))
  const boundIncrement = bindActionCreators(increment, dispatch);
  
  // 绑定一个action creators构成的object
  const boundActionCreators = bindActionCreators({ increment, decrement, reset }, dispatch);
  // 返回值:
  // {
  //   increment: (...args) => dispatch(increment(...args)),
  //   decrement: (...args) => dispatch(decrement(...args)),
  //   reset: (...args) => dispatch(reset(...args)),
  // }

在mapDispatchToProps中使用bindActionCreators函数:

import { bindActionCreators } from "redux";
// ...

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement, reset }, dispatch);
}

// 组件能接收到 props.increment, props.decrement, props.reset
connect(
  null,
  mapDispatchToProps
)(Counter);

总结

 React-redux常用方法已经介绍完了;个人总结就是在React-redux中使用还是很简单的;在主入口写入之后,通过connect函数可以轻松实现state的action和dispatch;可能需要注意的就是在编写组件的时候尽量把每个的action、reducer分开起来写;方便管理;控制;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章