1、定义与功能react
React-Redux 将全部组件分红两大类:UI 组件(presentational component)和容器组件(container component)算法
一、UI 组件特征:redux
this.state
这个变量)this.props
)提供二、容器组件特征:ide
总结:函数
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。性能
React-Redux 规定,全部的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。也就是说,用户负责视觉层,状态管理则是所有交给它。this
2、使用与方法spa
一、connect方法 输入UI组件, 输出容器组件code
React-Redux 提供connect
方法,用于从 UI 组件生成容器组件。component
// TodoList-> UI组件; VisibleTodoList -> 容器组件 // mapStatetoProps,mapDispatchToProps -> 它们定义了 UI 组件的业务逻辑。 // mapStatetoProps 可省略,若省略,UI 组件就不会订阅Store,就是说 Store 的更新不会引发 UI 组件的更新 import { connect } from 'react-redux' const VisibleTodoList = connect(mapStatetoProps, mapDispatchToProps)(TodoList);
(1) mapStateToProps(
state
[,props
]) 负责输入逻辑,即将state
映射到 UI 组件的参数(props
)
state: 必选,
state
对象;props: 可选,
表明容器组件的
props
对象mapStateToProps
会订阅 Store,每当state
更新的时候,就会自动执行,从新计算 UI 组件的参数(props),从而触发 UI 组件的从新渲染。
// map Redux state to component props (把 Redux state 映射到 component props) const mapStatetoProps = (state) => { return {num: state} } // 使用ownProps做为参数后,若容器组件的参数(ownProps)发生变化,也会引起 UI 组件从新渲染 const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } }
(2) mapDispatchToProps 负责输出逻辑,即将用户对 UI 组件的操做映射成 Action。
// map Redux actions to component props (把 Redux actions 映射到 component props) const mapDispatchToProps = dispatch => { return { onIncreaseClick: () => dispatch(increaseAction) }; }
mapDispatchToProps 分为两种类型:函数和对象
mapDispatchToProps
是一个函数,会获得dispatch
和ownProps
(容器组件的props
对象)两个参数。
mapDispatchToProps
做为函数,应该返回一个对象,该对象的每一个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action
const mapDispatchToProps = ( dispatch, ownProps ) => { return { onClick: () => { dispatch({ type: 'SET_VISIBILITY_FILTER', filter: ownProps.filter }); } }; }
mapDispatchToProps
是一个对象,键名是对应 UI 组件的同名参数,键值应该是一个函数,会被看成 Action creator ,返回的 Action 会由 Redux 自动发出
const mapDispatchToProps = { onClick: (filter) => { type: 'SET_VISIBILITY_FILTER', filter: filter }; }
3、原理与流程
为了让子组件可以得到context属性,React强制要求根组件(此处为Provider组件)提供getChildContext实例方法,以及类属性childContextTypes。而子组件想要获取context,也必须定义类级别的Counter. contextTypes属性。定义是双向的,若是缺乏了任何一块,子组件都获取不到context属性。
我认为父组件的那块定义是在Provider的代码中实现的,而子组件的那部分是在connect方法中实现的。
所以connect方法为Counter组件添加的context属性实质上是由Provider传下来的,这样在mapStatesToProps方法里的state参数实质上就是this.context.store.getState()方法得到的。
页面首次加载以及以后有互动行为以后整个逻辑的流程:
(1)页面首次加载时,store里的初始state获取过程:
createStore(reducers,defaultParams)的调用,其中reducers可使一个reducer,也但是redux.combineReducers过的reducer的集合。
createStore方法会对每一个reducer去dispatch一个action.type=@@redux/INIT类型的action,而这个action通常在reducer的代码里不会被handle,直接掉入default块,因而就返回了state的初始状态。
而后通常就会ReactDom.render()将应用渲染出来,每一个子组件的容器组件经过传入this.context.store.getState()方法得到的state对象, 以及容器组件上自带的ownProps给mapStatesToProperties方法,来构建props,最后将props应用到子组件的UI组件上。
(2)互动行为以后整个逻辑:
当在子组件上发生交互行为,如click时,mapDispatchToProps会定义click触发时应该dispatch哪个action的映射。而后store接收到这个action后会进行reduce,获得最新的state,而后再调用全部的子组件的mapStatesToProps方法生成新的props。最后对Provider进行从新渲染。固然上面的事件计算出来的不少state可能都不会发生变化,因此diff算法不会去修改这些没有发生变化的组件,所以性能也比较好。