API
<Provider store>
使得層級之下的組件可以通過connect()
函數(shù)訪問到Redux store。通常渣蜗,如果你不將父組件或者根組件用<Provider>
組件包裹起來的話庶香,你是不可以使用connect()
函數(shù)的。
Props
-
store
(Redux Store): 應(yīng)用中的單一數(shù)據(jù)源 -
children
(ReactElement) :你的根組件
Example
Vanilla React
ReactDOM.render(
<Provider store={store}>
<MyRootComponent />
</Provider>,
rootEl
)
React Router
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<Route path="foo" component={Foo}/>
<Route path="bar" component={Bar}/>
</Route>
</Router>
</Provider>,
document.getElementById('root')
)
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
將一個React組件連接到Redux store上去康铭。connect
是connectAdvanced
的一層包裝棒卷,對外提供了一套對于大多數(shù)開發(fā)情況下方便的API。
它并不更改傳入的組件碧绞,而是返回一個新的府框、連接到store的組件共你使用庶香。
Arguments
-
[mapStateToProps(state, [ownProps]): stateProps] (Function):如果這個參數(shù)指定了拄显,這個新組件將會訂閱store的更新责蝠。這意味著每次store更新守问,
mapStateToProps
將會被調(diào)用咱士。mapStateToProps
的結(jié)果是一個plain object米酬,這個結(jié)果會和組件的props融合為新的props骑丸。如果你不想訂閱store的更新霎冯,傳入null或者undefined发魄。如果你的
mapStateToProps
傳入了兩個參數(shù)盹牧,那么調(diào)用它時,store將會作為第一個參數(shù)欠母,connected component的props將會作為第二個參數(shù)欢策,并且也會重新觸發(fā),如果判定機(jī)制——淺相等比較判斷組件接收到新的props赏淌。注意:在你需要對渲染性能有更多的控制的情況下踩寇,
mapStateToProps
也可以返回一個函數(shù)。在這種情況下六水,那個返回的函數(shù)將被特定的組件作為mapStateTOProps
俺孙。這使得你可以完成單一實例記憶化(per-instance memoization
)You can refer to #279 and the tests it adds for more details. 大多數(shù)應(yīng)用不需要用到它。當(dāng)
mapStateToProps
接受一個store參數(shù)時掷贾,它將返回一個對象睛榄,這個對象將作為組建的props。我們通常將其稱作selector想帅,Use reselect to efficiently compose selectors and compute derived data. -
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function):如果傳入的是object场靴,每一個其中的函數(shù)都應(yīng)該是一個Redux action creator。一個擁有同樣的函數(shù)的對象將會融合入組件的props港准,但不同的是這個對象的每個action creator將會作為dispatch的參數(shù)旨剥,這樣它們就可以直接執(zhí)行。
如果傳入的是一個函數(shù)浅缸,那么這個函數(shù)將會接受dispatch作為它的第一個參數(shù)轨帜。It’s up to you to return an object that somehow uses dispatch
to bind action creators in your own way. (Tip: you may use the bindActionCreators()
helper from Redux.)如果你的
mapDispatchToProps
傳入了兩個參數(shù),那么dispatch將作為第一個參數(shù)衩椒,被連接的組件傳入的props將作為第二個參數(shù)蚌父。每當(dāng)組將接收到新的參數(shù)時哮兰,這個函數(shù)都將被觸發(fā)。如果你不指定
mapDispatchToProps
參數(shù)苟弛,那么默認(rèn)的mapDispatchToProps
實現(xiàn)會將dispatch作為props連接的組件喝滞。Note: in advanced scenarios where you need more control over the rendering performance, mapDispatchToProps()
can also return a function. In this case, that function will be used as mapDispatchToProps()
for a particular component instance. This allows you to do per-instance memoization. You can refer to #279 and the tests it adds for more details. Most apps never need this. [mergeProps(stateProps, dispatchProps, ownProps): props] (Function):如果這個函數(shù)指定了,那么傳入這個函數(shù)的前兩個參數(shù)分別為
mapStateToProps(), mapDispatchToProps()
的執(zhí)行結(jié)果嗡午,第三個參數(shù)為組件自身的props囤躁。這個函數(shù)將會返回一個plain object,這個結(jié)果將成為被包裹組件的props荔睹。你也許可以用這個回調(diào)函數(shù)狸演,根據(jù)組件的 props 來篩選部分的 state 數(shù)據(jù),或者把 props 中的某個特定變量與 action creator 綁定在一起僻他。如果你省略這個參數(shù)宵距,默認(rèn)情況下返回Object.assign({}, ownProps, stateProps, dispatchProps)
的結(jié)果。-
[options] (Object):如果指定這個參數(shù)吨拗,可以進(jìn)一步定制connector的行為满哪。除了
connectAdvanced()
可以傳入的選項之外,connect()
還可以接收以下的額外選項劝篷。- [
pure
](Boolean):如果為true哨鸭,當(dāng)相關(guān)的state/props的相等判斷機(jī)制判斷其沒有發(fā)生變化時,connect()
將會避免組建的重新render()
以及mapStateToProps, mapDispatchToProps, mergeProps
的調(diào)用娇妓,前提是該組件是一個“純”組件像鸡,即該組件不依賴于任何外部的輸入和內(nèi)部的state,只依賴于props和從connect()
函數(shù)獲取到的store的數(shù)據(jù)哈恰。默認(rèn)值為true只估。
- [
areStatesEqual
] (Function): When pure, compares incoming store state to its previous value. Default value:strictEqual (===)
- [
areOwnPropsEqual
] (Function): When pure, compares incoming props to its previous value. Default value:shallowEqual
- [
areStatePropsEqual
] (Function): When pure, compares the result ofmapStateToProps
to its previous value. Default value:shallowEqual
- [
areMergedPropsEqual
] (Function): When pure, compares the result ofmergeProps
to its previous value. Default value:shallowEqual
- [
storeKey
] (String): The key of the context from where to read the store. You probably only need this if you are in the inadvisable position of having multiple stores. Default value:'store'
- [
mapStateToProps和mapDispatchToProps函數(shù)的元數(shù)(arity,可以理解為函數(shù)長度)決定了它們是否能接收到ownProps作為第二個參數(shù)着绷。
注意:如果定義一個包含強(qiáng)制性參數(shù)函數(shù)(這個函數(shù)的長度為 1)時蛔钙,
ownProps
不會傳到mapStateToProps
和mapDispatchToProps
中。舉個例子荠医,如下這樣定義一個函數(shù)時將不會接收到 ownProps 作為第二個參數(shù)吁脱。
function mapStateToProps(state) {
console.log(state); // state
console.log(arguments[1]); // undefined
}
//因為這個函數(shù)有一個參數(shù)有默認(rèn)值,所以這個函數(shù)的長度仍然為1
const mapStateToProps = (state, ownProps = {}) => {
console.log(state); // state
console.log(ownProps); // undefined
}
當(dāng)函數(shù)沒有強(qiáng)制性的參數(shù)或兩個參數(shù)時將接收到 ownProps
彬向。
const mapStateToProps = (state, ownProps) => {
console.log(state); // state
console.log(ownProps); // ownProps
}
function mapStateToProps() {
console.log(arguments[0]); // state
console.log(arguments[1]); // ownProps
}
const mapStateToProps = (...args) => {
console.log(args[0]); // state
console.log(args[1]); // ownProps
}
Optimizing(優(yōu)化) connect when options.pure is true
當(dāng)options.pure
為true
的時候豫喧,connect
將執(zhí)行幾個相等檢測,以此避免不必要的mapStateToProps, mapDispatchToProps, mergeProps
調(diào)用幢泼,最終導(dǎo)致render()
。這些相等檢測包括areStatesEqual
, areOwnPropsEqual
, areStatePropsEqual
, 和areMergedPropsEqual
讲衫。盡管默認(rèn)參數(shù)可能適合于99%的場景缕棵,但是出于性能或者其他原因孵班,你也許像自定義它們的實現(xiàn),下面是幾個例子招驴。
如果
mapStateToProps
需要花費昂貴的計算時間并且只關(guān)心你的狀態(tài)的一小部分篙程,那么你可以重寫areStatesEqual
。舉個例子:areStatesEqual: (next, prev) => prev.entities.todos === next.entities.todos
别厘。當(dāng)你使用不純的reducers時虱饿,你或許希望重寫
areStatesEqual
,使它一直返回false触趴。You may wish to override
areOwnPropsEqual
as a way to whitelist incoming props. You'd also have to implementmapStateToProps
,mapDispatchToProps
andmergeProps
to also whitelist props. (It may be simpler to achieve this other ways, for example by using recompose's mapProps.)You may wish to override
areStatePropsEqual
to usestrictEqual
if yourmapStateToProps
uses a memoized selector that will only return a new object if a relevant prop has changed. This would be a very slight performance improvement, since would avoid extra equality checks on individual props each timemapStateToProps
is called.You may wish to override
areMergedPropsEqual
to implement adeepEqual
if your selectors produce complex props. ex: nested objects, new arrays, etc. (The deep equal check should be faster than just re-rendering.)
返回值
根據(jù)配置信息氮发,返回一個注入了 state 和 action creator 的 React高階組件。這個組件是由connectAdvanced
創(chuàng)建的冗懦。
例子
Inject just dispatch
and don't listen to store
export default connect()(TodoApp)
Inject all action creators (addTodo
, completeTodo
, ...) without subscribing to the store
import * as actionCreators from './actionCreators'
export default connect(null, actionCreators)(TodoApp)
Inject dispatch
and every field in the global state
Don’t do this! It kills any performance optimizations because
TodoApp
will rerender after every state change.
It’s better to have more granularconnect()
on several components in your view hierarchy that each only
listen to a relevant slice of the state.
export default connect(state => state)(TodoApp)
Inject dispatch
and todos
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps)(TodoApp)
Inject todos
and all action creators
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps, actionCreators)(TodoApp)
Inject todos
and all action creators (addTodo
, completeTodo
, ...) as actions
import * as actionCreators from './actionCreators'
import { bindActionCreators } from 'redux'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) }
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
and a specific action creator (addTodo
)
import { addTodo } from './actionCreators'
import { bindActionCreators } from 'redux'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ addTodo }, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
and specific action creators (addTodo
and deleteTodo
) with shorthand syntax
import { addTodo, deleteTodo } from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
const mapDispatchToProps = {
addTodo,
deleteTodo
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
, todoActionCreators as todoActions
, and counterActionCreators as counterActions
import * as todoActionCreators from './todoActionCreators'
import * as counterActionCreators from './counterActionCreators'
import { bindActionCreators } from 'redux'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return {
todoActions: bindActionCreators(todoActionCreators, dispatch),
counterActions: bindActionCreators(counterActionCreators, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
, and todoActionCreators and counterActionCreators together as actions
import * as todoActionCreators from './todoActionCreators'
import * as counterActionCreators from './counterActionCreators'
import { bindActionCreators } from 'redux'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
, and all todoActionCreators and counterActionCreators directly as props
import * as todoActionCreators from './todoActionCreators'
import * as counterActionCreators from './counterActionCreators'
import { bindActionCreators } from 'redux'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
Inject todos
of a specific user depending on props
import * as actionCreators from './actionCreators'
function mapStateToProps(state, ownProps) {
return { todos: state.todos[ownProps.userId] }
}
export default connect(mapStateToProps)(TodoApp)
Inject todos
of a specific user depending on props, and inject props.userId
into the action
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
function mergeProps(stateProps, dispatchProps, ownProps) {
return Object.assign({}, ownProps, {
todos: stateProps.todos[ownProps.userId],
addTodo: (text) => dispatchProps.addTodo(ownProps.userId, text)
})
}
export default connect(mapStateToProps, actionCreators, mergeProps)(TodoApp)
Factory functions
Factory functions can be used for performance optimizations
import { addTodo } from './actionCreators'
function mapStateToPropsFactory(initialState, initialProps) {
const getSomeProperty= createSelector(...);
const anotherProperty = 200 + initialState[initialProps.another];
return function(state){
return {
anotherProperty,
someProperty: getSomeProperty(state),
todos: state.todos
}
}
}
function mapDispatchToPropsFactory(initialState, initialProps) {
function goToSomeLink(){
initialProps.history.push('some/link');
}
return function(dispatch){
return {
addTodo
}
}
}
export default connect(mapStateToPropsFactory, mapDispatchToPropsFactory)(TodoApp)
connectAdvanced(selectorFactory, [connectOptions])
將一個React組件連接到redux store上去爽冕。它是connect()
的基礎(chǔ),但是對于如何將state
披蕉,props
颈畸,dispatch
結(jié)合到最終的props上沒有那么固定的限制。它不會對默認(rèn)值或結(jié)果的記憶做任何假設(shè)没讲,而是將這些責(zé)任留給調(diào)用者眯娱。
Arguments
- selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function):