connect簡介
react-redux僅有2個API,Provider和connect,Provider提供的是一個頂層容器的作用,實現(xiàn)store的上下文傳遞。
原理解析
首先connect之所以會成功,是因為Provider組件:
在原應(yīng)用組件上包裹一層,使原來整個應(yīng)用成為Provider的子組件
接收Redux的store作為props,通過context對象傳遞給子孫組件上的connect
那connect做了些什么呢?
它真正連接 Redux 和 React,它包在我們的容器組件的外一層,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,傳給一個構(gòu)造函數(shù),返回一個對象,以屬性形式傳給我們的容器組件。
connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {})
connect作用:連接React組件與 Redux store。
connect真正連接的是容器型組件,容器型組件主要關(guān)注業(yè)務(wù)邏輯的處理,比如從服務(wù)器拉取數(shù)據(jù),進(jìn)行數(shù)據(jù)校驗等,容器組件處理好的數(shù)據(jù)再通過props傳遞給需要使用的展示型組件,展示型組件是關(guān)注界面渲染的組件。
一個應(yīng)用(或頁面)中可以有多個容器型組件,這取決于你的業(yè)務(wù)邏輯復(fù)雜程度,一般最外層的組件是會做為一個容器組件進(jìn)行connect(但這不是必須),當(dāng)你層級較低的組件中有較多業(yè)務(wù)邏輯需要處理時,往往也會在它的上一層封裝一個容器組件專門處理這些邏輯,這時這個組件也是會被connect的。
使用 connect() 前,需要先定義 mapStateToProps 這個函數(shù)來指定如何把當(dāng)前 Redux store state 映射到展示組件的 props 中。例如,VisibleTodoList 需要計算傳到 TodoList 中的 todos,所以定義了根據(jù) state.visibilityFilter 來過濾 state.todos 的方法,并在 mapStateToProps 中使用。
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
case 'SHOW_ALL':
default:
return todos
}
}
const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
除了讀取 state,容器組件還能分發(fā) action。類似的方式,可以定義 mapDispatchToProps() 方法接收 dispatch() 方法并返回期望注入到展示組件的 props 中的回調(diào)方法。例如,我們希望 VisibleTodoList向 TodoList 組件中注入一個叫 onTodoClick 的 props ,還希望 onTodoClick 能分發(fā) TOGGLE_TODO 這個 action:
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
最后,使用 connect() 創(chuàng)建 VisibleTodoList,并傳入這兩個函數(shù)。
import { connect } from 'react-redux'
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
connect和@connect的區(qū)別
The @ symbol is in fact a JavaScript expression currently proposed to signify decorators:
Decorators make it possible to annotate and modify classes and properties at design time.
Here's an example of setting up Redux without and with a decorator:
Without a decorator
import React from 'react';
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) };
}
class MyApp extends React.Component {
// ...define your main app here
}
export default connect(mapStateToProps, mapDispatchToProps)(MyApp);
Using a decorator
import React from 'react';
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
function mapStateToProps(state) {
return { todos: state.todos };
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) };
}
@connect(mapStateToProps, mapDispatchToProps)
export default class MyApp extends React.Component {
// ...define your main app here
}
From What's the '@' (at symbol) in the Redux @connect decorator?
為什么我們需要react-redux?
熟悉redux的人可能知道,redux是數(shù)據(jù)存儲和管理的工具,但是想要在react中使用redux,并不能直接將store、action和react組件建立連接,所以就需要react-redux來結(jié)合react和redux。
Redux 的工作流程,Reducer 的拆分
從何處開始解析react-redux源碼?
1、在JavaScript中,讀懂別人的代碼文件,你首先應(yīng)該看的是函數(shù)的入口。
2、找到函數(shù)入口,然后看有哪些參數(shù)。
3、看看導(dǎo)入了哪些額外的插件,每個插件的作用大概預(yù)測一下。
4、進(jìn)入函數(shù)體進(jìn)行解讀。
如何發(fā)送網(wǎng)絡(luò)請求
當(dāng)我們需要從服務(wù)器獲取數(shù)據(jù)時,我們應(yīng)該在組件的哪一個生命周期方法中發(fā)送網(wǎng)絡(luò)請求呢?React官網(wǎng)上提到,可以在componentDidMount中發(fā)送網(wǎng)絡(luò)請求,這也是一般情況下的最佳實踐。有些人也會把發(fā)送網(wǎng)絡(luò)請求放在componentWillMount中,并且認(rèn)為這個方法先于componentDidMount調(diào)用,所以可以更快地獲取數(shù)據(jù)。個人認(rèn)為,這種使用方法一般也是沒有問題的,但在一些場景下會出現(xiàn)問題,比如需要在服務(wù)器端渲染時,componentWillMount會被調(diào)用兩次,一次是在Server端,一次是在Client端。可參考這篇文章。
詳見