API

<Provider store>

<Provider store> 使组件层级中的 connect() 方法都能够获得 Redux store。正常情况下,你的根组件应该嵌套在 <Provider> 中才能使用 connect() 方法。

如果你真的不想把根组件嵌套在 <Provider> 中,你可以把 store 作为 props 传递到每一个被 connect() 包装的组件,但是我们只推荐您在单元测试中对 store 进行伪造 (stub) 或者在非完全基于 React 的代码中才这样做。正常情况下,你应该使用 <Provider>

属性

  • store (Redux Store): 应用程序中唯一的 Redux store 对象
  • children (ReactElement) 组件层级的根组件。

例子

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。

连接操作不会改变原来的组件类。
反而返回一个新的已与 Redux store 连接的组件类。

参数

  • [mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store。如果指定了该回调函数中的第二个参数 ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用(例如,当 props 接收到来自父组件一个小小的改动,那么你所使用的 ownProps 参数,mapStateToProps 都会被重新计算)。

注意:在高级章节中,你需要更好地去控制渲染的性能,所用到的 mapStateToProps() 会返回一个函数。在这种情况下,那个函数将被作为 mapStateToProps() 在独有的组件实例中调用。这样就允许你在每一个实例中去记录。你可以参考 #279 去测试和了解其中的详细内容。但在绝大多数的应用中不会用到。

  • [mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将 action creator 的返回值作为参数执行。这些属性会被合并到组件的 props 中。

如果传递的是一个函数,该函数将接收一个 dispatch 函数,然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(提示:你也许会用到 Redux 的辅助函数 bindActionCreators()。如果你省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中。如果指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用。

注意:在高级章节中,你需要更好地去控制渲染的性能,所用到的 mapStateToProps() 会返回一个函数。但在这个例子中,这个函数将被 mapStateToProps() 在独有的组件实例中调用。这样就允许你在每一个实例中去记录。你可以参考 #279 去测试和了解其中的详细内容。但在绝大多数的应用中不会用到。 mapStateToProps 函数的第一个参数是整个 Redux store 的 state,它返回一个要作为 props 传递的对象。它通常被称作 selector (选择器)。 可以使用reselect去有效地组合选择器和计算衍生数据.

  • [mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了这个参数,mapStateToProps()mapDispatchToProps() 的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 action creator 绑定在一起。如果你省略这个参数,默认情况下返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果。

  • [options] (Object) 如果指定这个参数,可以定制 connector 的行为。

  • [pure = true] (Boolean): 如果为 true,connector 将执行 shouldComponentUpdate 并且浅对比 mergeProps 的结果,避免不必要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true
  • [withRef = false] (Boolean): 如果为 true,connector 会保存一个对被被包含的组件实例的引用,该引用通过 getWrappedInstance() 方法获得。默认值为 false

注意:如果定义一个包含强制性参数函数(这个函数的长度为 1)时,ownProps 不会传到 mapStateToPropsmapDispatchToProps 中。举个例子,如下这样定义一个函数时将不会接收到 ownProps 作为第二个参数。

function mapStateToProps(state) {
  console.log(state) // state
  console.log(arguments[1]) // undefined
}
const mapStateToProps = (state, ownProps = {}) => {
  console.log(state) // state
  console.log(ownProps) // undefined
}

当函数没有强制性的参数或两个参数时将接收到 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
}

返回值

根据配置信息,返回一个注入了 state 和 action creator 的 React 组件。

静态属性
  • WrappedComponent (Component): 传递到 connect() 函数的原始组件类。
静态方法

组件原来的静态方法都被提升到被包装的 React 组件。

实例方法
getWrappedInstance(): ReactComponent

仅当 connect() 函数的第四个参数 options 设置了 { withRef: true } 才返回被包装的组件实例。

备注

  • 函数将被调用两次。第一次是设置参数,第二次是组件与 Redux store 连接:connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)

  • connect 函数不会修改传入的 React 组件,返回的是一个新的已与 Redux store 连接的组件,而且你应该使用这个新组件。

  • mapStateToProps 函数接收整个 Redux store 的 state 作为 props,然后返回一个传入到组件 props 的对象。该函数被称之为 selector。参考使用 reselect 高效地组合多个 selector ,并对 收集到的数据进行处理

Examples 例子

只注入 dispatch,不监听 store
export default connect()(TodoApp)
注入全部没有订阅 store 的 action creators (addTodo, completeTodo, ...)
import * as actionCreators from './actionCreators'

export default connect(
  null,
  actionCreators
)(TodoApp)
注入 dispatch 和全局 state

不要这样做!这会导致每次 action 都触发整个 TodoApp 重新渲染,你做的所有性能优化都将付之东流。

最好在多个组件上使用 connect(),每个组件只监听它所关联的部分 state。

export default connect(state => state)(TodoApp)
注入 dispatchtodos
function mapStateToProps(state) {
  return { todos: state.todos }
}

export default connect(mapStateToProps)(TodoApp)
注入 todos 和所有 action creator
import * as actionCreators from './actionCreators'

function mapStateToProps(state) {
  return { todos: state.todos }
}

export default connect(
  mapStateToProps,
  actionCreators
)(TodoApp)
注入 todos 并把所有 action creator (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 和指定的 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)
简写语法注入 todos 和特定的 action 创建函数(addTodo and 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(
      Object.assign({}, todoActionCreators, counterActionCreators),
      dispatch
    )
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoApp)
注入 todos 并把所有的 todoActionCreators 和 counterActionCreators 作为 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)
根据组件的 props 注入特定用户的 todos
import * as actionCreators from './actionCreators'

function mapStateToProps(state, ownProps) {
  return { todos: state.todos[ownProps.userId] }
}

export default connect(mapStateToProps)(TodoApp)
根据组件的 props 注入特定用户的 todos 并把 props.userId 传入到 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)函数

工厂函数可用于性能优化。

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() 的基础,但是对于如何把state, props, 和 dispatch 组合到最后的 props 中,则不那么自以为是。它不对默认值或结果的记录做任何假设,而是将这些责任留给调用者。

它不修改传递给它的组件类;相反,它返回一个新的、已连接的组件类,供您使用。

参数

  • selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function):初始化选择器函数 (在每个实例的构造函数中)。该选择器函数是在 connector 组件需要重新计算一个新的 props 时调用,作为 store 的 state 改变或者接收到一个新的 props 的结果。selector 的结果应该是一个普通对象,作为被包裹的组件的 props 传递。如果连续调用 selector 都返回与上一次调用相同的对象(===),则不会重新渲染该组件。selector 的责任是在适当的时候返回以前的对象。

  • [connectOptions] (Object) 如果指定,则进一步自定义连接器(connector)的行为。

  • [getDisplayName] (Function): 计算连接器组件相对于被包裹的组件的 DisplayName 属性。 通常被包裹函数覆盖。 默认值: name => 'ConnectAdvanced('+name+')'

  • [methodName] (String):显示在错误消息中。 通常被包裹函数覆盖。 默认值: 'connectAdvanced'

  • [renderCountProp] (String): 如果被定义, 名为此值的属性将添加到传递给被包裹组件的 props 中。它的值将是组件被渲染的次数,这对于跟踪不必要的重新渲染非常有用。默认值: undefined

  • [shouldHandleStateChanges] (Boolean): 控制连接器(connector)组件是否订阅 redux store 的 state 更改。 如果设置为 false,则只会在componentWillReceiveProps中重新渲染。 默认值: true

  • [storeKey] (String): 可以获取 store 的 props/context key。 当你不明智地使用了多个 store 的时候,你才可能需要这个。默认值: 'store'

  • [withRef] (Boolean): 如果为 true,则将一个引用存储到被包裹的组件实例中,并通过 getWrappedInstance() 方法使其可用。 默认值: false

  • 此外,通过 connectOptions 传递的任何额外选项都将传递给 factorOptions 参数中的 selectorFactory

返回值

一个高阶 React 组件类,它从 store 的 state 生成 props 并将它们传递给被包裹的组件。高阶组件是接受组件参数并返回新组件的函数.

静态属性
  • WrappedComponent (Component): 原始组件类传递给 connectAdvanced(...)(Component).
静态函数

组件的所有原始静态方法都被挂起。

实例方法
getWrappedInstance(): ReactComponent

返回被包裹组件的实例。只有当你传递 { withRef: true } 作为options 的参数才可用。

注意

  • 因为 connectAdvanced 返回一个高阶组件,所以需要调用它两次。 第一次使用上面描述的参数,第二次使用组件: connectAdvanced(selectorFactory)(MyComponent).

  • connectAdvanced 不修改传递的 React 组件。它返回一个新的连接组件,您应该使用它。

例子

根据 props 将特定用户的 todos 注入,并将 pros.userid 注入到操作中
import * as actionCreators from './actionCreators'
import { bindActionCreators } from 'redux'

function selectorFactory(dispatch) {
  let ownProps = {}
  let result = {}
  const actions = bindActionCreators(actionCreators, dispatch)
  const addTodo = text => actions.addTodo(ownProps.userId, text)
  return (nextState, nextOwnProps) => {
    const todos = nextState.todos[nextOwnProps.userId]
    const nextResult = { ...nextOwnProps, todos, addTodo }
    ownProps = nextOwnProps
    if (!shallowEqual(result, nextResult)) result = nextResult
    return result
  }
}
export default connectAdvanced(selectorFactory)(TodoApp)

createProvider([storeKey])

创建一个新的<Provider>,它将在上下文的传递 key 上设置 Redux Store。 当你不明智地使用了多个 store 的时候,你才可能需要这个。您还需要将相同的 storeKey 传递给connectoptions 参数。

参数

  • storeKey: The key of the context on which to set the store.要在其上设置 store 的上下文的 key。 默认值: 'store'

例子

在创建多个 store 之前,请浏览以下常见问题: 我是否可以或应该创建多个 store?

import { connect, createProvider } from 'react-redux'

const STORE_KEY = 'componentStore'

export const Provider = createProvider(STORE_KEY)

function connectExtended(
  mapStateToProps,
  mapDispatchToProps,
  mergeProps,
  options = {}
) {
  options.storeKey = STORE_KEY
  return connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    options
  )
}

export { connectExtended as connect }

现在,您可以 import 上面的 Providerconnect 并使用它们。