严格的单向数据流是 Redux 架构的设计核心,使用 Redux 的一个好处就是让 state 的变化过程变的可预知和透明。javascript
Redux约定使用普通对象object tree来描述应用的 state ,若是想更新 state 中的数据,须要先发起一个 action请求来对更改进行描述,而后调用 reducer函数执行state更改。java
Store 就是用来维持应用全部的 state 的一个对象。react
getState()
git
返回应用当前的 state 树;github
dispatch(action : object)
:json
分发 action 改变 store;redux
subscribe(listener : Function)
: 数组
注册监听器, 每当 dispatch action 的时候就会执行; state 树中的一部分可能已经变化, 能够在回调函数里调用 getState()
来拿到当前 state。promise
replaceReducer(nextReducer : Function)
:架构
用 nextReducer 替换当前 store 的 reducer。在须要实现代码分隔,并且须要当即加载一些 reducer 的时候才可能会用到它,在实现 Redux 热加载机制的时候也可能会用到。
建立一个 Redux store 来以存放应用中全部的 state:createStore(reducer, [preloadedState], enhancer)
参数
reducer(): Function
接收两个参数,分别是当前的 state 树和要处理的action,返回新的state 树。
preloadedState: any
初始化state。 若是使用 combineReducers 建立 reducer,它必须是一个普通对象,与传入的 keys 保持一样的结构;不然能够自由传入任何 reducer 可理解的内容。
enhancer: Function
Store enhancer 是一个组合 store creator 的高阶函数,返回一个新的强化过的 store creator。
返回值
Store
: 保存了应用全部 state 的对象。
栗子
import React from 'react' import { createStore } from 'redux' import reducer from './reducers' const store = createStore(reducer);
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的惟一来源。action 内必须使用一个字符串类型的 type
字段来表示将要执行的动做。
type
会被定义成字符串常量。{ type: ADD_TODO, text: 'Build my first Redux app' }
Action Creator 就是生成 action 的方法。
function fetchPosts(url) { return { type: FETCH_POSTS, url } }
store 里直接经过 store.dispatch()
调用 action,可是多数状况下会使用 react-redux 提供的 connect()
来调用。bindActionCreators()
能够自动把多个 action 建立函数 绑定到 dispatch()
方法上。
一个约定俗成的作法是经过建立函数生成 action 对象,而不是在dispatch 的时候内联生成action。
// 1. 内联生成 action store.dispatch({ type: ADD_TODO, text: 'Build my first Redux app' }) // 2. Action Creator 生成 action function fetchPosts(url) { return { type: FETCH_POSTS, url } } store.dispatch(fetchPosts(url))
Redux 的应用程序中最多见的 state 结构是一个简单的 JavaScript 对象,它最外层的每一个 key 中拥有特定域的数据。给这种 state 结构写 reducer 的方式是分拆成多个 reducer,拆分以后的 reducer 都是相同的结构(state, action),而且每一个函数独立负责管理该特定切片 state 的更新。多个拆分以后的 reducer 能够响应一个 action,在须要的状况下独立的更新他们本身的切片 state,最后组合成新的 state。
function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }); default: return state; } }
这是一个高阶 Reducer ,combineReducers
接收拆分以后的 reducer 函数组成的对象,而且建立出具备相同键对应状态对象的Reducer函数。目前 combineReducers
只能处理普通的 JavaScript 对象。
若是没有给 createStore
提供预加载 state,输出 state 对象的 key 将由输入的拆分以后 reducer 组成对象的 key 决定。
结合Immutable.js 使用
combineReducers 不解决 Immutable.js,Maps等构建的 state tree,也不会把其他部分的 state 做为额外参数传递给 reducer 或者排列 reducer 的调用顺序,它一样不关心 reducer 如何工做。如今有大量提供相似功能的工具,例如 redux-immutable,这个第三方包实现了一个可以处理 Immutable Map 数据而非普通的 JavaScript 对象的 combineReducers
。
栗子
1.定义reducers
/** * reducers.js */ function info(state = {}, action) { switch (action.type) { case 'UPDATE_NAME': return { ...state, name: action.text }; case 'UPDATE_SCHOOL': return { ...state, school: action.text }; default: return state } } function age(state = {}, action) { switch (action.type) { case 'INCREMENT_AGE': return { ...state, age: state.age + 1 }; case 'DECREMENT_AGE': return { ...state, age: state.age - 1 } default: return state } } export { info, age };
2.建立store, 引入combineReducers
/** * App.js */ import { createStore, combineReducers } from 'redux' import { info, age } from './reducers.js' let store = createStore(combineReducers({ info, age }), { name: '', school: '', age: 0 }); console.log(store.getState()) // { // info: { name: '', school: '' }, // age: 0 // } store.dispatch({ type: 'UPDATE_NAME', text: 'Use Redux' }) console.log(store.getState()) // { // info: { name: 'Use Redux', school: '' }, // age: 0 // }
同步: Action 发出之后,Reducer 当即算出 State;
异步:Action 发出之后,过一段时间再执行 Reducer;
默认状况下,createStore()
所建立的 Redux store 只支持同步数据流, dispatch
只能接收一个普通对象。怎么才能在异步操做结束后Reducer自动执行呢?这时就须要使用中间件。
Redux middleware 提供的是 action 被发起以后,到达 reducer 以前的扩展点,在每一个 action 对象 dispatch 出去以前,注入一个自定义的逻辑来解释 action 对象。
中间件能够进行日志记录、建立崩溃报告、调用异步接口或者路由等等;在applyMiddleware
方法里把中间件做为参数传入。此方法是 Redux 的原生方法,做用是将全部中间件组成一个数组,依次执行。
applyMiddleware(...middleware)
参数
...middleware
遵循 Redux middleware API 的函数。每一个 middleware 接受 Store
的 dispatch
和 getState
函数做为命名参数,并返回一个函数。该函数会被传入被称为 next
的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数能够直接调用 next(action)
,或者在其余须要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store 的 dispatch
方法做为 next
参数,并借此结束调用链。因此,middleware 的函数签名是 ({ getState, dispatch }) => next => action
。
返回值
(Function) :一个应用了 middleware 后的 store enhancer。这个 store enhancer 的签名是 createStore => createStore
,可是最简单的使用方法就是直接做为最后一个 enhancer
参数传递给 createStore()
函数。
实现请求先后打日志, 请求失败处理异常的中间件:
import { createStore, combineReducers, applyMiddleware } from 'redux'; import reducers from './reducers' // 请求先后日志记录middleware const logger = store => next => action => { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } // 请求异常记录middleware const crashReporter = store => next => action => { try { return next(action) } catch (err) { console.error('Caught an exception!', err) Raven.captureException(err, { extra: { action, state: store.getState() } }) throw err } } // createStore引入本身建立的middleware const store = createStore( combineReducers(reducers), preloadedState, applyMiddleware(logger, crashReporter) )
从右到左来组合多个函数: compose(...functions)
compose(funcA, funcB, funcC)
形象为 compose(funcA(funcB(funcC())))
参数
(arguments): 须要合成的多个函数。预计每一个函数都接收一个参数。它的返回值将做为一个参数提供给它左边的函数,以此类推
返回值
(Function): 从右到左把接收到的函数合成后的最终函数。
react-redux是使用redux开发react时使用的一个插件。react-redux提供了两个重要的API:Provider、connect
。
<Provider>
API<Provider>
使组件层级中的 connect()
方法都可以得到 Redux store。
正常状况下,你的根组件应该嵌套在 <Provider>
中才能使用 connect()
方法。若是不想把根组件嵌套在 <Provider>
中,你能够把 store
做为 props 传递到每个被 connect()
包装的组件。
属性
store
: 应用程序中惟一的 Redux store 对象;children: ReactElement
: 组件层级的根组件;栗子
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
connect
API链接 React 组件与 Redux store。链接操做不会改变原来的组件类, 返回一个新的已与 Redux store 链接的组件类。connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
参数
mapStateToProps(state, [ownProps]): Function
stateProps。
mapStateToProps
函数若是定义了就会被调用;ownProps
,则该参数的值为传递到组件的 props。只要组件接收新的 props,mapStateToProps
也会被调用。(例如,当父组件从新渲染子组件props改变,那么 ownProps 参数,mapStateToProps 都会被从新计算)该函数必须返回一个纯对象,这个对象会与组件的 props 合并。
mapDispatchToProps(dispatch, [ownProps]):(Object / Function)
dispatchProps。
dispatch
方法会将 action creator 的返回值做为参数执行。这些属性会被合并到组件的 props 中。dispatch
函数,返回值是一个对象。返回对象经过 dispatch
函数与 action creator 以某种方式绑定在一块儿。mapDispatchToProps
,默认状况下,dispatch
会注入到你的组件 props 中。ownProps
,该参数的值为传递到组件的 props,并且只要组件接收到新 props,mapDispatchToProps
也会被调用。mergeProps(stateProps, dispatchProps, ownProps): Function]
props。
mapStateToProps()
与 mapDispatchToProps()
的执行结果和组件自身的 props
将传入到这个回调函数中。(Object.assign({}, ownProps, stateProps, dispatchProps)
的结果。options: Object
若是指定这个参数,能够定制 connect 的行为;
pure = true
] (Boolean): 若是为 true,connector 将执行 shouldComponentUpdate
而且浅对比 mergeProps
的结果,避免没必要要的更新,前提是当前组件是一个“纯”组件,它不依赖于任何的输入或 state 而只依赖于 props 和 Redux store 的 state。默认值为 true
。withRef = false
] (Boolean): 若是为 true,connector 会保存一个对被包含的组件实例的引用,该引用经过 getWrappedInstance()
方法得到。默认值为 false
。返回值
根据配置信息,返回一个注入了 state 和 action creator 的 React 组件。
redux-thunk是redux解决异步的中间件, 可让 Action Creator 返回函数(普通的 Action Creator 默认返回一个对象)。若是action creator 返回的是一个函数,就执行它,若是不是,就按照原来的next(action)执行。
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import reducer from './reducers'; const store = createStore( reducer, applyMiddleware(thunk) );
redux-thunkexport default
的是createThunkMiddleware()
,这个函数返回的是一个柯里化过的函数。
function createThunkMiddleware(extraArgument) { return function({ dispatch, getState }) { return function(next){ return function(action){ if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } } }
栗子
fetchPosts
返回了一个函数,而普通的 Action Creator 默认返回一个对象。dispatch
和getState
,而普通的 Action Creator 的参数是 Action 的内容。requestPosts(title)
,表示操做开始。const fetchPosts = title => (dispatch, getState) => { dispatch(requestPosts(title)); return fetch(url) .then(response => response.json()) .then(json => dispatch(receivePosts(title, json))); }; }; store.dispatch(fetchPosts('test'));
既然使用redux-thunk中间件可让 Action Creator 返回函数,固然也能够返回其余值。另外一种异步操做的解决方案是让 Action Creator 返回一个 Promise 对象。这就须要使用redux-promise
中间件。
import { createStore, applyMiddleware } from 'redux'; import promiseMiddleware from 'redux-promise'; import reducer from './reducers'; const store = createStore( reducer, applyMiddleware(promiseMiddleware) );
栗子
const fetchPosts = (dispatch, title) => new Promise((resolve, reject)=> { dispatch(requestPosts(title)); return fetch(url).then(response => { type: 'FETCH_POSTS', payload: response.json() }); });
Redux 让状态管理变得很冗长,大量的action、actionCreator、reducer让开发者不断在写重复的代码。redux-actions就解决了这个问题,让编写redux状态管理变得简单起来。
主要API有createAction(s)
、handleAction(s)
、combineActions
。
建立一个action: createAction(type)
import { createAction } from 'redux-actions'; export const increment = createAction('INCREMENT'); export const decrement = createAction('DECREMENT'); increment(); // { type: 'INCREMENT' } decrement(); // { type: 'DECREMENT' } increment(10); // { type: 'INCREMENT', payload: 10 } decrement([1, 42]); // { type: 'DECREMENT', payload: [1, 42] }
建立多个action: createActions(actionMap, ...identityActions[, options])
第一个参数 actionMap 是一个对象,以 action type 为键名,键值value有三种形式:
action
建立的时候传入的参数,返回结果会做为到生成的action
的payload
的value。createActions({ ADD_TODO: todo => ({ todo }), // payload creator REMOVE_TODO: [ todo => ({ todo }), // payload creator (todo, warn) => ({ todo, warn }) // meta ] });
处理action
,返回一个reducer
,处理一种类型的action type
。
处理一个action: handleAction(type, reducer, defaultState)
import { handleAction } from 'redux-actions'; handleAction( 'APP/COUNTER/INCREMENT', (state, action) => ({ counter: state.counter + action.payload.amount }), defaultState );
处理多个action: handleActions(reducerMap, defaultState[, options])
const reducer = handleActions( { INCREMENT: (state, action) => ({ counter: state.counter + action.payload }), DECREMENT: (state, action) => ({ counter: state.counter - action.payload }) }, { counter: 0 } );
React Developer Tools、Redux DevTools 能够给开发人员在研发阶段调试程序带来极大的方便。 可是上了生产环境后,应该将禁止 DevTools。
Redux DevTools的做者已经给出了标准的解决方案。具体实现步骤以下:
process.env.NODE_ENV = JSON.stringify('production')
redux-devtools-extension/developmentOnly
引入方法import { createStore, applyMiddleware } from 'redux'; import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; const store = createStore( rootReducer, composeWithDevTools(middlewareEnhancer) );