跳至主要內容

connect()

提示

connect 仍然可在 React-Redux 8.x 中使用且受到支援。但是,我們建議使用 hook API 作為預設值

概觀

connect() 函式可將 React 元件連線至 Redux 儲存體。

它可提供所連線之元件所需資料的部分,以及可用的函式來將 action 傳送至儲存體。

它不會修改傳入的元件類別;而是回傳新的已連線元件類別,將您傳入的元件包裝起來。

function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)

mapStateToPropsmapDispatchToProps 分別處理 Redux 儲存體的 statedispatchstatedispatch 會供應給您的 mapStateToPropsmapDispatchToProps 函式作為第一個參數。

mapStateToPropsmapDispatchToProps 的回傳值分別在內部被稱為 statePropsdispatchProps。它們將會提供給已定義的 mergeProps,分別作為第一個和第二個引數,而第三個引數將會是 ownProps。所整合的結果通常稱為 mergedProps,然後將會提供給您連接的元件。

connect() 參數

connect 接受四個不同的參數,全部都是選用的。依慣例,它們稱為

  1. mapStateToProps?: 函式
  2. mapDispatchToProps?: 函式 | 物件
  3. mergeProps?: 函式
  4. options?: 物件

mapStateToProps?: (state, ownProps?) => 物件

如果指定了 mapStateToProps 函式,則新的包裝器元件將訂閱 Redux 儲存更新。這表示只要儲存更新,就會呼叫 mapStateToPropsmapStateToProps 的結果必須是純粹的物件,將會合併到已包裝的元件屬性中。如果不希望訂閱儲存更新,請傳遞 nullundefined 代替 mapStateToProps

參數

  1. state: 物件
  2. 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 a mapDispatchToProps 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 alebo mapDispatchToProps 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

  1. dispatch: Funkcia
  2. 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 a mapDispatchToProps 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 alebo mapDispatchToProps 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` 的結果。

  1. stateProps
  2. dispatchProps
  3. 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 也提供 nextOwnPropsprevOwnProps,以利在必要時更有效地設定已連接元件感興趣的狀態範圍。

這可能會影響其他的等值檢查,視您的 mapStateToProps 函式而定。

areOwnPropsEqual: (next: Object, prev: Object) => boolean

  • 預設值:shallowEqual: (objA, objB) => boolean (當物件中的每個欄位都相等時,傳回 true )

比對傳入的 props 與其前一個值。

您或許會改寫 areOwnPropsEqual,以將傳入的 props 加入白名單中。您也必須實作 mapStateToPropsmapDispatchToPropsmergeProps,才能將 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)
  • 注入所有動作建立函式(addTodocompleteTodo 等)而不訂閱 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)
  • 注入 dispatchtodos
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 和所有動作建立函式(addTodocompleteTodo 等)做為 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 和特定的動作建立函式(addTododeleteTodo)採用簡短的語法
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,將 todoActionCreatorscounterActionCreators 一起做為 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,並直接注入所有 todoActionCreatorscounterActionCreators 做為屬性
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

mapStateToPropsmapDispatchToProps 宣告的函數參數數目決定它們是否接收 ownProps

注意:如果函數的形式定義包含一個必要參數(函數長度為 1),ownProps 就會不被傳遞至 mapStateToPropsmapDispatchToProps。例如,像下面定義的函數不會將 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
}

函數工廠

如果您的 mapStateToPropsmapDispatchToProps 函數回傳一個函數,它們將在元件實例建立時呼叫一次,而且其回傳值將在後續呼叫時分別作為實際的 mapStateToPropsmapDispatchToProps 函數使用。

函數工廠通常與暫存選擇器一起使用。這讓您可以在封閉區域內建立元件實例特定的選擇器

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 儲存庫的這些封存檔案