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分開起來寫;方便管理;控制;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章