說明
本篇文章是根據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抽取數據
參數:
- state
- 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分開起來寫;方便管理;控制;