晴明的博客园 GitHub      CodePen      CodeWars     

[react] redux

#

react-redux
容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)

任何一个从 connect() 包装好的组件都可以得到一个 dispatch 方法作为组件的 props,以及得到全局 state 中所需的任何内容。
 connect() 的唯一参数是 selector。此方法可以从 Redux store 接收到全局的 state,然后返回组件中需要的 props。
 最简单的情况下,可以返回一个初始的 state (例如,返回认证方法),但最好先将其进行转化。

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


#React Router 里的写法

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>...</Router>
  </Provider>,
  targetEl
);

 

connect
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 也会被调用。

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function):
如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,
而且这个对象会与 Redux store 绑定在一起,其中所定义的方法名将作为属性名,合并到组件的 props 中。
如果传递的是一个函数,该函数将接收一个 dispatch 函数,
然后由你来决定如何返回一个对象,这个对象通过 dispatch 函数与 action creator 以某种方式绑定在一起(bindActionCreators())。
如果省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到组件 props 中。
如果指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,
而且只要组件接收到新 props,mapDispatchToProps 也会被调用。


[mergeProps(stateProps, dispatchProps, ownProps): props] (Function)


[options] (Object)

 


#只注入 dispatch,不监听 store

export default connect()(TodoApp);

#注入 dispatch 和全局 state(不推荐这样写)

export default connect(state => state)(TodoApp);

#注入 dispatch 和 todos

function mapStateToProps(state) {
  return { todos: state.todos };
}
export default connect(mapStateToProps)(TodoApp);

#注入 todos 和所有 action creator (addTodo, completeTodo, ...)

import * as actionCreators from './actionCreators';
function mapStateToProps(state) {
  return { todos: state.todos };
}
export default connect(mapStateToProps, actionCreators)(TodoApp);

#注入 todos 并把所有 action creator 作为 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 并把 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);

 





bindActionCreators
bindActionCreators(actionCreators, dispatch)

actionCreators (Function or Object): 一个 action creator,或者键值是 action creators 的对象。
dispatch (Function): 一个 dispatch 函数,由 Store 实例提供。
    
使用 bindActionCreators 的场景是当你需要把 action creator 往下传到一个组件上,
却不想让这个组件觉察到 Redux 的存在,而且不希望把 Redux store 或 dispatch 传给它。

#TodoActionCreators.js

export function addTodo(text) {
  return {
    type: 'ADD_TODO',
    text
  };
}

export function removeTodo(id) {
  return {
    type: 'REMOVE_TODO',
    id
  };
}

#SomeComponent.js

import { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

import * as TodoActionCreators from './TodoActionCreators';
console.log(TodoActionCreators);
// {
//   addTodo: Function,
//   removeTodo: Function
// }

class TodoListContainer extends Component {
  componentDidMount() {
    // 由 react-redux 注入:
    let { dispatch } = this.props;

    // 注意:这样做行不通:
    // TodoActionCreators.addTodo('Use Redux');

    // 你只是调用了创建 action 的方法。
    // 你必须要 dispatch action 而已。

    // 这样做行得通:
    let action = TodoActionCreators.addTodo('Use Redux');
    dispatch(action);
  }

  render() {
    // 由 react-redux 注入:
    let { todos, dispatch } = this.props;

    // 这是应用 bindActionCreators 比较好的场景:
    // 在子组件里,可以完全不知道 Redux 的存在。

    let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
    console.log(boundActionCreators);
    // {
    //   addTodo: Function,
    //   removeTodo: Function
    // }

    return (
      <TodoList todos={todos}
                {...boundActionCreators} />
    );

    // 一种可以替换 bindActionCreators 的做法是直接把 dispatch 函数
    // 和 action creators 当作 props 
    // 传递给子组件
    // return <TodoList todos={todos} dispatch={dispatch} />;
  }
}

export default connect(
  state => ({ todos: state.todos })
)(TodoListContainer)

 

posted @ 2016-05-26 14:00  晴明桑  阅读(319)  评论(0编辑  收藏  举报