Store
。组件每次从新渲染,都必须由状态变化引发。action
。reducer
函数接收action
,而后根据当前的state
,计算出新的state
。state
(状态)。经过限制更新发生的时间和方式,Redux 试图让 state
的变化变得可预测。{ type: 'LIKE_ARTICLE', articleId: 42 };
{ type: 'FETCH_USER_SUCCESS', response: { id: 3, name: 'Mary' } };
{ type: 'ADD_TODO', text: 'Read the Redux docs.'};复制代码
action
理解成新闻的摘要。如 “玛丽喜欢42号文章。” 或者 “任务列表里添加了'学习 Redux 文档'”。store.dispatch(action)
,包括组件中、XHR 回调中、甚至定时器中。reducer
: 当前的 state
树和 action
。例如,在这个 todo
应用中,根 reducer
可能接收这样的数据:// 当前应用的 state(todos 列表和选中的过滤器)
let previousState = {
visibleTodoFilter: 'SHOW_ALL',
todos: [
{
text: 'Read the docs.',
complete: false
}
]
}
// 将要执行的 action(添加一个 todo)
let action = {
type: 'ADD_TODO',
text: 'Understand the flow.'
}
// render 返回处理后的应用状态
let nextState = todoApp(previousState, action);复制代码
dispatch(action)
前发生。reducer
的结构彻底由你决定。Redux 原生提供combineReducers()
辅助函数,来把根 reducer
拆分红多个函数,用于分别处理 state
树的一个分支。-下面演示 combineReducers() 如何使用。假如你有两个 reducer:一个是 todo 列表,另外一个是当前选择的过滤器设置:javascript
function todos(state = [], action) {
// 省略处理逻辑...
return nextState;
}
function visibleTodoFilter(state = 'SHOW_ALL', action) {
// 省略处理逻辑...
return nextState;
}
let todoApp = combineReducers({
todos,
visibleTodoFilter
})复制代码
action
后,combineReducers
返回的 todoApp
会负责调用两个 reducer:let nextTodos = todos(state.todos, action);
let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action);复制代码
return {
todos: nextTodos,
visibleTodoFilter: nextVisibleTodoFilter
};复制代码
combineReducers()
是一个很方便的辅助工具,你也能够选择不用;你能够自行实现本身的根 reducer
!这个新的树就是应用的下一个 state!全部订阅 store.subscribe(listener) 的监听器都将被调用;监听器里能够调用 store.getState() 得到当前 state。java
如今,能够应用新的 state
来更新 UI。若是你使用了 React Redux 这类的绑定库,这时就应该调用 component.setState(newState)
来更新。react
state
被储存在一棵 object tree
中,而且这个 object tree
只存在于惟一一个 store
中。 state
的方法就是触发 action
,action
是一个用于描述已发生事件的普通对象。action
如何改变 state tree
,你须要编写 reducers
。store
,这个store
有Redux提供的createStore(reducers,[initialState])
方法生成。从函数签名看出,想生成store
,必须传入reducers
,同时也能够传入第二个可选参数初始化状态initialState
。使用方法 const store = createStore(reducer);
redux
action
并修改数据的角色就是reducer
。reducer
本质上是一个纯函数,其函数签名为reducer(previousState, action) => newState
。reducer
在处理action
时,需传入一个previousState
参数。reducer
的职责就是根据previousState
和action
来计算出新的newState
。使用方法将reducer
即下面的todo
做为参数传入createStore(todo)中数组
//如下为reducer的格式
const todo = (state = initialState, action) => {
switch(action.type) {
case 'XXX':
return //具体的业务逻辑;
case 'XXX':
return //具体的业务逻辑;
default:
return state;
}
}复制代码
getState()
store
中的状态。store.dispatch(action)
action
,并返回这个action
,这是惟一能改变store
中数据的方式。store.dispatch接受一个Action对象做为参数,将它发送出去。store.subscribe(listenter)
store
发生变化时被调用,一旦State发生了变化,就会自动执行这个函数。经过subscribe绑定了一个监听函数以后,只要dispatch了一个action,全部监听函数都会自动执行一遍。store
里的reducer
,通常只会在开发者模式中调用该方法。包含getState()
,dispatch(action)
,subscribe(listener)
;本函数近似源码,可简单实现功能与帮助理解createStore
的原理app
const createStore = (reducer) => {
let state; //声明一个变量承接状态
let list = [];//声明一个数组用于储存监听函数
const getState = () => {
return state;//直接返回state;
}
const dispatch = (action) =>{
state = reducer(state, action);//更新状态,且循环list数组,并执行里面的事件
list.forEach((fn) => {
fn();
})
}
const subscribe = (fn) => {
list.push(fn);//将函数传入list中
return () => {
list = list.filter(cd => cd != fn)
}
}
return {
getState,
subscribe,
dispatch
}
}复制代码
reducer
函数 进行拆分,拆分后的每一块独立负责管理 state
的一部分。combineReducers
辅助函数的做用是,把一个由多个不一样 reducer
函数做为 value
的 object
,合并成一个最终的 reducer
函数,而后就能够对这个 reducer
调用 createStore
。reducer
做为对象的属性传入combineReducers({})
函数中,const rootReducer = combineReducers({
reducer1,
reducer2,
...
})复制代码
(Function):一个调用 reducers 对象里全部 reducer 的 reducer,而且构造一个与 reducers 对象结构相同的 state 对象。ide
let store = createStore(rootReducer)
//store = {
reducer1: ... ,
reducer2: ... ,
...
}
let {reducer1, reducer2} = store; //取出复制代码
//研究逻辑看这个
const combineReducers = (reducers) => {
return (state = {}, action) => {
let newState = {};
Object.keys(reducers).forEach((key) =>{
newState[key] = reducers[key](state[key], action);
})
return newState;
}
}
//简写装逼看这个
const combineReducers = (reducers) => (state = {}, action) => Object.keys(reducers).reduce((newState, key) => {
newState[key] = reducers[key](state[key], action);
return newState;
},{})复制代码
prop
一层层传递下去固然是没问题的。不过这也太麻烦啦,要是能在最外层和最里层之间开一个穿越空间的虫洞就行了。Context
。注意:context
一直都在React源码中,但在React0.14版本才被记录官方文档。官方并不太推荐大量使用,虽然它能够减小逐级传递,但当组件复杂时,咱们并不知道context
是从哪传来的。它就相似于全局变量。函数
在外层定义一个getChildContext
方法,在父层制定childContextTypes
。工具
class Provider extends Component{
getChildContext() {
return {store: ...};
}
render(){
return(
this.props.children
)
}
}
Provider.childContextTypes = {
store : React.PropTypes.object
};复制代码
在内层设置组件的contextTypes
后,便可在组件里经过this.context.
来访问。学习
class child extends Component{
render(){
const store = this.context.store;
return(
<div>1</div>
)
}
}
child.contextTypes = {
store: React.PropTypes.object
}复制代码
createStore()
方法,这样还不足以让Redux在咱们的react应用中发挥做用,还须要react-redux库 ———— Redux官方提供的React绑定。<Provider />
, 一个是connect()
。关于它们,咱们须要知道的是,<Provider />
接受一个store
做为props
,它是整个Redux应用的顶层组件,而connect()
提供了在整个React应用的任意组件中获取store
中数据的功能。其实就是建立一个外层包裹住整个Redux应用。
<Provider />
主要源码
export default class Provider extends Component {
getChildContext() {
return { store: this.store }
}
constructor(props, context) {
super(props, context)
this.store = props.store
}
render() {
return Children.only(this.props.children)
}
}复制代码
ReactDom.render(
<Provider store = {store}> <App /> </Provider>,
document.getElementById("root")
)复制代码
使用方法connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(TodoApp)
上面代码看似那么长,但其实理解起来不太难,前四个参数是选填属性,根据需求填入便可。connect(...)
调用后会返回一个函数这个函数可传一个参数,即你须要绑定的组件。
connect
函数,只针对前两个关键参数。const connect = (mapStateToProps, mapDispatchToProps) => {
return (WrapperComponent) => {
class Connect extends Component {
componentDidMount() {
const store = this.context.store;
this.unsubscribe = store.subscribe(() => {
this.forceUpdate();
})
}
componentWillUnmount() {
this.unsubscribe();
}
render (){
const store = this.context.store;
const stateProps = mapStateToProps(store.getState());
const dispatchProps = mapDispatchToProps(store.dispatch);
const props = Object.assign({}, stateProps, dispatchProps);
// return <WrapperComponent {...props} />;
return React.createElement(WrapperComponent, props);
}
}
Connect.contextTypes = {
store: React.PropTypes.object
};
return Connect;
}
}复制代码
官方解释: 若是定义该参数,组件将会监听 Redux store
的变化。任什么时候候,只要 Redux store
发生改变,mapStateToProps
函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props
合并。若是你省略了这个参数,你的组件将不会监听 Redux store
。若是指定了该回调函数中的第二个参数 ownProps
,则该参数的值为传递到组件的 props
,并且只要组件接收到新的 props
,mapStateToProps
也会被调用。
使用方法(其实里面第一个参数就是最先在 <Provider store = {store}>
传入的store
,因而能够在子组件上访问store
里的属性)
const mapStateToProps = (state, [ownProps]) => {
return {
todos : state.todos
}
}复制代码
action creator
,并且这个对象会与 Redux store
绑定在一块儿,其中所定义的方法名将做为属性名,合并到组件的 props
中。若是传递的是一个函数,该函数将接收一个 dispatch
函数,而后由你来决定如何返回一个对象,这个对象经过 dispatch
函数与 action creator
以某种方式绑定在一块儿(提示:你也许会用到 Redux 的辅助函数 bindActionCreators())。若是你省略这个 mapDispatchToProps
参数,默认状况下,dispatch
会注入到你的组件 props
中。若是指定了该回调函数中第二个参数 ownProps
,该参数的值为传递到组件的 props
,并且只要组件接收到新 props
,mapDispatchToProps
也会被调用。mapStateToProps
是用来传递属性状态的,而mapDispatchToProps
是用来传递改变的方法的。const mapDispatchToProps = (dispatch, [ownProps]) => {
return{
... : () => {
dispatch(...)
}
}
}复制代码
mergeProps(stateProps, dispatchProps, ownProps)
能够接受stateProps, dispatchProps, ownProps三个参数。stateProps
就是传给connect
的第一个参数mapStateToProps
最终返回的props
。dispatchProps
就是传给connect
的第二个参数mapDispatchToProps
最终返回的props
。ownProps
则为组件本身的props
。若是指定这个参数,能够定制 connector 的行为。
[pure = true] (Boolean): 若是为 true
,connector
将执行 shouldComponentUpdate
而且浅对比 mergeProps
的结果,避免没必要要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state
而只依赖于 props
和 Redux store
的 state
。默认值为 true
。
[withRef = false] (Boolean): 若是为 true
,connector
会保存一个对被包装组件实例的引用,该引用经过 getWrappedInstance()
方法得到。默认值为 false
。