connect()
connect
仍然可在 React-Redux 8.x 中使用且受到支援。但是,我們建議使用 hook API 作為預設值。
概觀
connect()
函式可將 React 元件連線至 Redux 儲存體。
它可提供所連線之元件所需資料的部分,以及可用的函式來將 action 傳送至儲存體。
它不會修改傳入的元件類別;而是回傳新的已連線元件類別,將您傳入的元件包裝起來。
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
mapStateToProps
和 mapDispatchToProps
分別處理 Redux 儲存體的 state
和 dispatch
。state
和 dispatch
會供應給您的 mapStateToProps
或 mapDispatchToProps
函式作為第一個參數。
mapStateToProps
及 mapDispatchToProps
的回傳值分別在內部被稱為 stateProps
及 dispatchProps
。它們將會提供給已定義的 mergeProps
,分別作為第一個和第二個引數,而第三個引數將會是 ownProps
。所整合的結果通常稱為 mergedProps
,然後將會提供給您連接的元件。
connect()
參數
connect
接受四個不同的參數,全部都是選用的。依慣例,它們稱為
mapStateToProps?: 函式
mapDispatchToProps?: 函式 | 物件
mergeProps?: 函式
options?: 物件
mapStateToProps?: (state, ownProps?) => 物件
如果指定了 mapStateToProps
函式,則新的包裝器元件將訂閱 Redux 儲存更新。這表示只要儲存更新,就會呼叫 mapStateToProps
。mapStateToProps
的結果必須是純粹的物件,將會合併到已包裝的元件屬性中。如果不希望訂閱儲存更新,請傳遞 null
或 undefined
代替 mapStateToProps
。
參數
state: 物件
ownProps?: 物件
mapStateToProps
函式最多會取得兩個參數。宣告函式參數(亦稱為項數)的數量會影響函式呼叫的時間。這也會判斷是否會接收 ownProps。在此查看註解 。
state
如果 mapStateToProps
函式宣告為接受一個參數,則每當儲存狀態變更時就會呼叫函式,並將儲存狀態當作唯一參數傳入。
const mapStateToProps = (state) => ({ todos: state.todos })
ownProps
如果 mapStateToProps
函式宣告為接受兩個參數,則每當儲存狀態變更或當包裝器元件收到新的屬性(基於淺層相等比較)時,就會呼叫函式。呼叫時會將儲存狀態當作第一個參數,將包裝器元件的屬性當作第二個參數傳入。
依慣例,第二個參數通常稱為 ownProps
。
const mapStateToProps = (state, ownProps) => ({
todo: state.todos[ownProps.id],
})
回傳
您的 mapStateToProps
函式預期回傳一個物件。這個物件通常稱為 stateProps
,會作為屬性合併到您連接的元件中。如果您定義了 mergeProps
,它將作為第一個參數提供給 mergeProps
。
mapStateToProps
的回傳值決定連接元件是否重新渲染 (詳細內容請參閱 此處)。
如需了解建議如何使用 mapStateToProps
的更多詳細資訊,請參閱 有關如何使用 mapStateToProps
的指南。
môžete definovať
mapStateToProps
amapDispatchToProps
ako továrenskú funkciu, t. j. vrátite funkciu namiesto objektu. V takomto prípade sa vaša vrátená funkcia bude považovať za skutočnúmapStateToProps
alebomapDispatchToProps
a bude sa volať v následných volaniach. Môžete si prečítať poznámky o továrenských funkciách alebo nášho sprievodcu optimalizácie výkonnosti.
mapDispatchToProps?: Object | (dispatch, ownProps?) => Object
Tento druhý parameter connect()
, bežne nazývaný mapDispatchToProps
, môže byť buď objekt, funkcia alebo nemusí byť poskytnutý.
Vaša súčasť dostane dispatch
predvolene, t. j. keď nepridáte druhý parameter do connect()
// do not pass `mapDispatchToProps`
connect()(MyComponent)
connect(mapState)(MyComponent)
connect(mapState, null, mergeProps, options)(MyComponent)
Ak definujete mapDispatchToProps
ako funkciu, bude vyvolaná maximálne s dvoma parametrami.
Parametre
dispatch: Funkcia
ownProps?: 物件
dispatch
Ak je mapDispatchToProps
deklarované ako funkcia prijímajúca jeden parameter, bude mu priradené dispatch
vášho store
.
const mapDispatchToProps = (dispatch) => {
return {
// dispatching plain actions
increment: () => dispatch({ type: 'INCREMENT' }),
decrement: () => dispatch({ type: 'DECREMENT' }),
reset: () => dispatch({ type: 'RESET' }),
}
}
ownProps
Ak je vaša funkcia mapDispatchToProps
deklarovaná tak, že prijíma dva parametre, bude vyvolaná s dispatch
ako prvým parametrom a rekvizitami odovzdanými funkcií obalu ako druhým parametrom a bude opätovne vyvolaná vždy, keď pripojený komponent prijme nové rekvizity.
依慣例,第二個參數通常稱為 ownProps
。
// binds on component re-rendering
<button onClick={() => this.props.toggleTodo(this.props.todoId)} />
// binds on `props` change
const mapDispatchToProps = (dispatch, ownProps) => ({
toggleTodo: () => dispatch(toggleTodo(ownProps.todoId)),
})
Počet deklarovaných parametrov funkcie mapDispatchToProps
určuje, či príjmu ownProps. Pozrite si poznámky tu.
Návraty
Predpokladá sa, že vaše funkcie mapDispatchToProps
vrátia objekt. Každé pole objektu by malo byť funkciou, ktorej volanie by malo odoslať akciu do obchodu.
Návrat vašich funkcií mapDispatchToProps
sa považuje za dispatchProps
. Budú zlúčené ako rekvizity do vašej pripojenej komponenty. Ak definujete mergeProps
, bude poskytnuté ako druhý parameter pre mergeProps
.
const createMyAction = () => ({ type: 'MY_ACTION' })
const mapDispatchToProps = (dispatch, ownProps) => {
const boundActions = bindActionCreators({ createMyAction }, dispatch)
return {
dispatchPlainObject: () => dispatch({ type: 'MY_ACTION' }),
dispatchActionCreatedByActionCreator: () => dispatch(createMyAction()),
...boundActions,
// you may return dispatch here
dispatch,
}
}
如需取得更多有關建議用法詳細資料,請參閱我們使用 mapDispatchToProps
的指南。
môžete definovať
mapStateToProps
amapDispatchToProps
ako továrenskú funkciu, t. j. vrátite funkciu namiesto objektu. V takomto prípade sa vaša vrátená funkcia bude považovať za skutočnúmapStateToProps
alebomapDispatchToProps
a bude sa volať v následných volaniach. Môžete si prečítať poznámky o továrenských funkciách alebo nášho sprievodcu optimalizácie výkonnosti.
物件簡寫格式
mapDispatchToProps
可能是一個物件,其中每個欄位都是 動作產生器。
import { addTodo, deleteTodo, toggleTodo } from './actionCreators'
const mapDispatchToProps = {
addTodo,
deleteTodo,
toggleTodo,
}
export default connect(null, mapDispatchToProps)(TodoApp)
在此情況下,React-Redux 會使用 `bindActionCreators` 將你的儲存體的 `dispatch` 繫結至每個動作產生器中。結果會視為 `dispatchProps`,它將會直接併入至已連接的組件,或作為第二個參數而提供給 `mergeProps`。
// internally, React-Redux calls bindActionCreators
// to bind the action creators to the dispatch of your store
bindActionCreators(mapDispatchToProps, dispatch)
我們在 `mapDispatchToProps` 指南中有一個章節說明物件簡寫格式的用法,在此。
mergeProps?: (stateProps, dispatchProps, ownProps) => Object
如果已指定,它會定義如何決定你自己的包裝組件的最後屬性。如果你沒有提供 `mergeProps`,你的包裝組件預設會接收 `{ ...ownProps, ...stateProps, ...dispatchProps }`。
參數
mergeProps
最多應使用三個參數指定。它們各別為 `mapStateToProps()`, `mapDispatchToProps()`, 與包裝組件的 `props` 的結果。
stateProps
dispatchProps
ownProps
你從中傳回的一般物件中的欄位將會用作包裝組件的屬性。你可以指定此函數,以根據屬性選取狀態區段,或將動作產生器繫結至此屬性特定的變數。
傳回
mergeProps
的傳回值會稱為 `mergedProps`,其欄位將會用作包裝組件的屬性。
注意:在 mergeProps 中建立新值會導致重新渲染。建議你暫存欄位以避免不必要的重新渲染。
options?: Object
{
context?: Object,
areStatesEqual?: Function,
areOwnPropsEqual?: Function,
areStatePropsEqual?: Function,
areMergedPropsEqual?: Function,
forwardRef?: boolean,
}
context: Object
注意:此參數僅支援 >= v6.0
React-Redux v6 允許您提供自訂的 context 實例,供 React-Redux 使用。您需要將 context 的實例同時傳送至 <Provider />
和您的已連接元件。您可以將 context 傳送至已連接元件,方法是將它在此處當作選項欄位傳遞,或是將它當作屬性傳至已連接元件予以呈現。
// const MyContext = React.createContext();
connect(mapStateToProps, mapDispatchToProps, null, { context: MyContext })(
MyComponent,
)
areStatesEqual: (next: Object, prev: Object, nextOwnProps: Object, prevOwnProps: Object) => boolean
- 預設值:
strictEqual: (next, prev) => prev === next
比對進來的儲存狀態與其前一個值。
const areStatesEqual = (next, prev) =>
prev.entities.todos === next.entities.todos
如果您 mapStateToProps
函式需要進行大量運算,而且僅關注於狀態的一小部份,您可能希望改寫 areStatesEqual
。上面的範例基本上會忽略除了狀態切片之外的所有狀態變更。此外,areStatesEqual
也提供 nextOwnProps
和 prevOwnProps
,以利在必要時更有效地設定已連接元件感興趣的狀態範圍。
這可能會影響其他的等值檢查,視您的 mapStateToProps
函式而定。
areOwnPropsEqual: (next: Object, prev: Object) => boolean
- 預設值:
shallowEqual: (objA, objB) => boolean
(當物件中的每個欄位都相等時,傳回true
)
比對傳入的 props 與其前一個值。
您或許會改寫 areOwnPropsEqual
,以將傳入的 props 加入白名單中。您也必須實作 mapStateToProps
、mapDispatchToProps
和 mergeProps
,才能將 props 加入白名單中。(透過其他方式來達成這個目的或許會比較簡單,例如使用 recompose's mapProps。)
areStatePropsEqual: (next: Object, prev: Object) => boolean
- 類型:
函式
- 預設值:
shallowEqual
比對 mapStateToProps
的結果與其前一個值。
areMergedPropsEqual: (next: Object, prev: Object) => boolean
- 預設值:
shallowEqual
比對 mergeProps
的結果與其前一個值。
若您的 mapStateToProps
使用備忘選取器,僅在相關屬性已變更時才會回傳新的物件,則您可能想覆寫 areStatePropsEqual
以使用 strictEqual
。這會是一個非常輕微效能提升,因為可避免在每次呼叫 mapStateToProps
時對各個屬性執行額外的相等性檢查。
若您的選取器產生複雜屬性,則您可能想覆寫 areMergedPropsEqual
來執行 deepEqual
。ex:巢狀物件、新陣列等。(深層相等檢查會比重新渲染還快。)
forwardRef: boolean
注意:此參數僅支援 >= v6.0
若已將 {forwardRef : true}
傳遞給 connect
,那麼加入已連接包裝元件的 ref 實際上會回傳已包裝元件的執行個體。
connect()
傳回值
connect()
回傳值是一個包裝函式,它接受您的元件並回傳一個包裝元件,其中帶有它注入的額外屬性。
import { login, logout } from './actionCreators'
const mapState = (state) => state.user
const mapDispatch = { login, logout }
// first call: returns a hoc that you can use to wrap any component
const connectUser = connect(mapState, mapDispatch)
// second call: returns the wrapper component with mergedProps
// you may use the hoc to enable different components to get the same behavior
const ConnectedUserLogin = connectUser(Login)
const ConnectedUserProfile = connectUser(Profile)
在多數情況下,包裝函式會馬上呼叫,而不會儲存在暫時性的變數中
import { login, logout } from './actionCreators'
const mapState = (state) => state.user
const mapDispatch = { login, logout }
// call connect to generate the wrapper function, and immediately call
// the wrapper function to generate the final wrapper component.
export default connect(mapState, mapDispatch)(Login)
範例用法
由於 connect
是如此地靈活,因此看到一些關於它如何呼叫的額外範例會很有幫助。
- 注入僅僅是
dispatch
並且不偵聽 Store
export default connect()(TodoApp)
- 注入所有動作建立函式(
addTodo
、completeTodo
等)而不訂閱 Store
import * as actionCreators from './actionCreators'
export default connect(null, actionCreators)(TodoApp)
- 注入
dispatch
和狀態中的每個欄位
這樣做不要!它會抹煞任何效能最佳化,因為在每次狀態變更後
TodoApp
都將重新渲染。在視圖階層中幾個元件使用更精細的connect()
較佳,每個元件只偵聽相應狀態切片。
// don't do this!
export default connect((state) => state)(TodoApp)
- 注入
dispatch
和todos
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps)(TodoApp)
- 注入
todos
和所有動作建立函式
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps, actionCreators)(TodoApp)
- 注入
todos
和所有動作建立函式(addTodo
、completeTodo
等)做為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)
- 注入
todos
和一個特定的動作建立函式(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)
- 注入
todos
和特定的動作建立函式(addTodo
和deleteTodo
)採用簡短的語法
import { addTodo, deleteTodo } from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
const mapDispatchToProps = {
addTodo,
deleteTodo,
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
- 注入
todos
、將todoActionCreators
做為todoActions
注入、將counterActionCreators
做為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)
- 注入
todos
,將todoActionCreators
和counterActionCreators
一起做為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(
{ ...todoActionCreators, ...counterActionCreators },
dispatch,
),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
- 注入
todos
,並直接注入所有todoActionCreators
和counterActionCreators
做為屬性
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(
{ ...todoActionCreators, ...counterActionCreators },
dispatch,
)
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)
- 注入依照屬性指定使用者的
todos
import * as actionCreators from './actionCreators'
function mapStateToProps(state, ownProps) {
return { todos: state.todos[ownProps.userId] }
}
export default connect(mapStateToProps)(TodoApp)
- 注入依照屬性指定使用者的
todos
,並將props.userId
注入動作
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)
備註
mapToProps
函數的 ariy
mapStateToProps
和 mapDispatchToProps
宣告的函數參數數目決定它們是否接收 ownProps
注意:如果函數的形式定義包含一個必要參數(函數長度為 1),
ownProps
就會不被傳遞至mapStateToProps
和mapDispatchToProps
。例如,像下面定義的函數不會將ownProps
視為第二個參數接收。如果傳入的ownProps
值為undefined
,將會使用預設參數值。
function mapStateToProps(state) {
console.log(state) // state
console.log(arguments[1]) // undefined
}
const mapStateToProps = (state, ownProps = {}) => {
console.log(state) // state
console.log(ownProps) // {}
}
沒有必要參數或兩個參數的函數*將會接收 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
}
函數工廠
如果您的 mapStateToProps
或 mapDispatchToProps
函數回傳一個函數,它們將在元件實例建立時呼叫一次,而且其回傳值將在後續呼叫時分別作為實際的 mapStateToProps
、mapDispatchToProps
函數使用。
函數工廠通常與暫存選擇器一起使用。這讓您可以在封閉區域內建立元件實例特定的選擇器
const makeUniqueSelectorInstance = () =>
createSelector([selectItems, selectItemId], (items, itemId) => items[itemId])
const makeMapState = (state) => {
const selectItemForThisComponent = makeUniqueSelectorInstance()
return function realMapState(state, ownProps) {
const item = selectItemForThisComponent(state, ownProps.itemId)
return { item }
}
}
export default connect(makeMapState)(SomeComponent)
舊版本文件
盡管 connect
API 在我們所有的主要版本之間幾乎完全保持 API 相容,選項和行為仍有些許修改。
有關舊版 5.x 和 6.x 版本的詳細資訊,請參考 React Redux 儲存庫的這些封存檔案