redux connect多个reducer怎么connect

标签:至少1个,最多5个
欢迎访问个人
随着WEB应用变得越来越复杂,再加上node前后端分离越来越流行,那么对数据流动的控制就显得越发重要。redux是在flux的基础上产生的,基本思想是保证数据的单向流动,同时便于控制、使用、测试。
redux不依赖于任意框架(库),只要subscribe相应框架(库)的内部方法,就可以使用该应用框架保证数据流动的一致性。
那么如何使用redux呢?下面一步步进行解析,并带有源码说明,不仅做到知其然,还要做到知其所以然。
2. 主干逻辑介绍(createStore)
2.1 简单demo入门
先来一个直观的认识:
// 首先定义一个改变数据的plain函数,成为reducer
function count (state, action) {
var defaultState = {
year: 2015,
state = state || defaultS
switch (action.type) {
case 'add':
year: state.year + 1
case 'sub':
year: state.year - 1
// store的创建
var createStore = require('redux').createS
var store = createStore(count);
// store里面的数据发生改变时,触发的回调函数
store.subscribe(function () {
console.log('the year is: ', store.getState().year);
// action: 触发state改变的唯一方法(按照redux的设计思路)
var action1 = { type: 'add' };
var action2 = { type: 'add' };
var action3 = { type: 'sub' };
// 改变store里面的方法
store.dispatch(action1); // 'the year is: 2016
store.dispatch(action2); // 'the year is: 2017
store.dispatch(action3); // 'the year is: 2016
2.2 挖掘createStore实现
为了说明主要问题,仅列出其中的关键代码,全部代码,可以点击阅读。
a 首先看createStore到底都返回的内容:
export default function createStore(reducer, initialState) {
subscribe,
replaceReducer
每个属性的含义是:
dispatch: 用于action的分发,改变store里面的state
subscribe: 注册listener,store里面state发生改变后,执行该listener
getState: 读取store里面的state
replaceReducer: 替换reducer,改变state修改的逻辑
b 关键代码解析
export default function createStore(reducer, initialState) {
// 这些都是闭包变量
var currentReducer = reducer
var currentState = initialState
var listeners = []
var isDispatching =
// 返回当前的state
function getState() {
return currentState
// 注册listener,同时返回一个取消事件注册的方法
function subscribe(listener) {
listeners.push(listener)
var isSubscribed = true
return function unsubscribe() {
if (!isSubscribed) {
isSubscribed = false
var index = listeners.indexOf(listener)
listeners.splice(index, 1)
// 通过action该改变state,然后执行subscribe注册的方法
function dispatch(action) {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
listeners.slice().forEach(listener =& listener())
return action
// 替换reducer,修改state变化的逻辑
function replaceReducer(nextReducer) {
currentReducer = nextReducer
dispatch({ type: ActionTypes.INIT })
// 初始化时,执行内部一个dispatch,得到初始state
dispatch({ type: ActionTypes.INIT })
如果还按照2.1的方式进行开发,那跟flux没有什么大的区别,需要手动解决很多问题,那redux如何将整个流程模板化(Boilerplate)呢?
3. 保证store的唯一性
随着应用越来越大,一方面,不能把所有的数据都放到一个reducer里面,另一方面,为每个reducer创建一个store,后续store的维护就显得比较麻烦。如何将二者统一起来呢?
3.1 demo入手
通过combineReducers将多个reducer合并成一个rootReducer:
// 创建两个reducer: count year
function count (state, action) {
state = state || {count: 1}
switch (action.type) {
function year (state, action) {
state = state || {year: 2015}
switch (action.type) {
// 将多个reducer合并成一个
var combineReducers = require('./').combineR
var rootReducer = combineReducers({
count: count,
year: year,
// 创建store,跟2.1没有任何区别
var createStore = require('./').createS
var store = createStore(rootReducer);
var util = require('util');
console.log(util.inspect(store));
//输出的结果,跟2.1的store在结构上不存在区别
// { dispatch: [Function: dispatch],
subscribe: [Function: subscribe],
getState: [Function: getState],
replaceReducer: [Function: replaceReducer]
3.2 源码解析combineReducers
// 高阶函数,最后返回一个reducer
export default function combineReducers(reducers) {
// 提出不合法的reducers, finalReducers就是一个闭包变量
var finalReducers = pick(reducers, (val) =& typeof val === 'function')
// 将各个reducer的初始state均设置为undefined
var defaultState = mapValues(finalReducers, () =& undefined)
// 一个总reducer,内部包含子reducer
return function combination(state = defaultState, action) {
var finalState = mapValues(finalReducers, (reducer, key) =& {
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
return nextStateForKey
return hasChanged ? finalState : state
4. 自动实现dispatch
4.1 demo介绍
在2.1中,要执行state的改变,需要手动dispatch:
var action = { type: '***', payload: '***'};
dispatch(action);
手动dispatch就显得啰嗦了,那么如何自动完成呢?
var bindActionCreators = require('redux').bindActionC
// 可以在具体的应用框架隐式进行该过程(例如react-redux的connect组件中)
bindActionCreators(action)
4.2 源码解析
// 隐式实现dispatch
function bindActionCreator(actionCreator, dispatch) {
return (...args) =& dispatch(actionCreator(...args))
export default function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
return mapValues(actionCreators, actionCreator =&
bindAQctionCreator(actionCreator, dispatch)
5. 支持插件 - 对dispatch的改造
5.1 插件使用demo
一个action可以是同步的,也可能是异步的,这是两种不同的情况, dispatch执行的时机是不一样的:
// 同步的action creator, store可以默认实现dispatch
function add() {
return { tyle: 'add' }
dispatch(add());
// 异步的action creator,因为异步完成的时间不确定,只能手工dispatch
function fetchDataAsync() {
return function (dispatch) {
requst(url).end(function (err, res) {
if (err) return dispatch({ type: 'SET_ERR', payload: err});
if (res.status === 'success') {
dispatch({ type: 'FETCH_SUCCESS', payload: res.data });
下面的问题就变成了,如何根据实际情况实现不同的dispatch方法,也即是根据需要实现不同的moddleware:
// 普通的dispatch创建方法
var store = createStore(reducer, initialState);
console.log(store.dispatch);
// 定制化的dispatch
var applyMiddleware = require('redux').applyM
// 实现action异步的middleware
var thunk = requre('redux-thunk');
var store = applyMiddleware([thunk])(createStore);
// 经过处理的dispatch方法
console.log(store.dispatch);
5.2 源码解析
// next: 其实就是createStore
export default function applyMiddleware(...middlewares) {
return (next) =& (reducer, initialState) =& {
var store = next(reducer, initialState)
var dispatch = store.dispatch
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: (action) =& dispatch(action)
chain = middlewares.map(middleware =& middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
dispatch // 实现新的dispatch方法
// 再看看redux-thunk的实现, next就是store里面的上一个dispatch
function thunkMiddleware({ dispatch, getState }) {
return function(next) {
return function(action) {
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
return next =& action =&
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
6. 与react框架的结合
6.1 基本使用
目前已经有现成的工具react-redux来实现二者的结合:
var rootReducers = combineReducers(reducers);
var store = createStore(rootReducers);
var Provider = require('react-redux').P
// App 为上层的Component
class App ponent{
render() {
&Provier store={store}&
&Container /&
&/Provider&
// Container作用: 1. 获取store中的数据; 2.将dispatch与actionCreator结合起来
var connect = require('react-redux').
var actionCreators = require('...');
// MyComponent是与redux无关的组件
var MyComponent = require('...');
function select(state) {
count: state.count
export default connect(select, actionCreators)(MyComponent)
6.2 Provider -- 提供store
React通过属性,可以将属性(props)直接给子孙component,无须通过props层层传递, Provider仅仅起到获得store,然后将其传递给子孙元素而已:
export default class Provider extends Component {
getChildContext() { // getChildContext: 将store传递给子孙component
return { store: this.store }
constructor(props, context) {
super(props, context)
this.store = props.store
componentWillReceiveProps(nextProps) {
const { store } = this
const { store: nextStore } = nextProps
if (store !== nextStore) {
warnAboutReceivingStore()
render() {
let { children } = this.props
return Children.only(children)
6.3 connect -- 获得store及dispatch(actionCreator)
connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数(wrapWithConnect),然后再将真正的Component作为参数传入wrapWithConnect(MyComponent),这样就生产出一个经过包裹的Connect组件,该组件具有如下特点:
通过this.context获取祖先Component的store
props包括stateProps、dispatchProps、parentProps,合并在一起得到nextState,作为props传给真正的Component
componentDidMount时,添加事件this.store.subscribe(this.handleChange),实现页面交互
shouldComponentUpdate时判断是否有避免进行渲染,提升页面性能,并得到nextState
componentWillUnmount时移除注册的事件this.handleChange
在非生产环境下,带有热重载功能
// 主要的代码逻辑
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 从祖先Component处获得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 对stateProps、dispatchProps、parentProps进行合并
this.updateState()
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
componentDidMount() {
// 改变Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
render() {
// 生成包裹组件Connect
&WrappedComponent {...this.nextState} /&
Connect.contextTypes = {
store: storeShape
7. redux与react-redux关系图
8 收藏&&|&&107
你可能感兴趣的文章
12 收藏,912
106 收藏,4.1k
4 收藏,445
本作品采用 署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
combineReducers源码那边貌似贴错了呢。
combineReducers源码那边貌似贴错了呢。
有所收获,谢谢分享
有所收获,谢谢分享
combineReducers 最后的return 是在combination中的
combineReducers 最后的return 是在combination中的
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
我要该,理由是:首先,先看看第一张图,图中展示了Redux的单向数据流,以及Action、Reducer和Store这三个核心概念。
下面就围绕上图,非别介绍Action、Reducer和Store这三个概念。
Action是一个对象,用来代表所有会引起状态(state)变化的行为(例如服务端的响应,页面上的用户操作)。
假如我们要实现一个任务管理系统,那么添加任务的Action对象就会是下面的形式:
type: 'ADD_TASK',
name: 'Read ES6 spec',
category: 'Reading'
Action对象是行为的描述,一般都会包含下面的信息:
一个字符串类型的type字段来表示将要执行的动作
需要传递给应用的其他数据信息(例子中的name和category),数据形式用户可以自定义
Action通过Action创建函数(Action Creator)来创建,Action Creator是一个函数,最终返回一个Action对象。
对于添加任务这个行为,对应的Action Creator如下:
function addTask(name, category) {
type: ADD_TASK,
Action对象仅仅是描述了行为的相关信息,至于如何通过特定的行为来更新state,就需要看看Reducer了。
关于Reducer,最简单的描述就是:
Reducer是一个函数
该函数接收两个参数,一个旧的状态previousState和一个Action对象
返回一个新的状态newState
根据上面的描述,Reducer函数就可以表示为:
(previousState, action) =& newState
Reducer函数的形式通常如下:
function reducer(state = [], action) {
// 处理不同action的代码
switch (action.type) {
case SPECIAL_ACTION:
// 根据SPECIAL_ACTION action更新state
// 返回新的state
return state
Actions描述了"what happened"的事实,Reducers则根据这些actions来更新state,而Store则是Actions和Reducers连接在一起的对象。
Store是Redux中数据的统一存储,维护着state的所有内容,所以Store的主要功能就是:
维护应用的state内容
提供getState()方法获取 state
提供dispatch(action)方法更新 state
提供subscribe(listener)方法注册监听器
看到Store提供的方法,就可以把Action、Reducer和Store联系在一起了:
Store通过dispatch(action)方法来接收不同的Action
根据Action对象的type和数据信息,Store对象可以通过Reducer函数来更新state的内容
下面就来看看第二张图,跟第一张图的差别不大,只是增加了中间件(Middleware)来处理Action。
在Redux中,Middlerwares主要的作用就是处理Action,Redux中的Action必须是一个plain object。但是为了实现异步的Action或其他功能,这个Action可能就是一个函数,或者是一个promise对象。这是就需要中间件帮助来处理这种特殊的Action了。
也就是说,Redux中的Middleware会对特定类型action做一定的转换,所以最后传给reducer的action一定是标准的plain object。
针对Action的特征,Reudx Middleware可以采取不同的操作:
可以选择传递给下一个中间件,如:next(action)
可以选择跳过某些中间件,如:dispatch(action)
或者更直接了当的结束传递,如:return。
Redux中常用的中间件:
:action可以是一个函数,用来发起异步请求。
:action可以是一个promise对象,用来更优雅的进行异步操作。
:action就是一个标准的plain object,用来记录action和nextState的。
经过前面的介绍,我们已经看到了Redux中的一些核心概念。Redux跟React没有直接的关系,本身可以支持React、Angular、Ember等等框架。
通过react-redux这个库,可以方便的将react和redux结合起来:react负责页面展现,redux负责维护/更新数据状态。
到这里,第三张图就展示了react-redux这个库的工作原理,react和redux是怎么联系到一起的。
react-redux中提供了两个重要功能模块Provider和connect,这两个模块保证了react和redux之间的通信,下面就分别看看这两个模块。
通过可以看到,Provide本质上是一个react组件。
export default class Provider extends Component {
getChildContext() {
return { store: this.store }
constructor(props, context) {
super(props, context)
this.store = props.store
render() {
const { children } = this.props
return Children.only(children)
Provider组件主要用到了react通过,可以将属性(props)直接给子孙component,无须通过props层层传递,从而减少组件的依赖关系。
connect方法的主要作用就是让Component与Store进行关联, Store的数据变化可以及时通知Views重新渲染。
任何一个通过connect()函数处理过的组件都可以得到一个dispatch方法作为组件的props,以及得到全局state中的所有内容。
通过]可以看到,connect函数运行后,会返回一个wrapWithConnect函数,该函数可以接收一个react组件,然后返回一个经过处理的Connect组件。
return function wrapWithConnect(WrappedComponent) {
class Connect extends Component {
constructor(props, context) {
// 从祖先Component处获得store
this.store = props.store || context.store
this.stateProps = computeStateProps(this.store, props)
this.dispatchProps = computeDispatchProps(this.store, props)
this.state = { storeState: null }
// 对stateProps、dispatchProps、parentProps进行合并
this.updateState()
shouldComponentUpdate(nextProps, nextState) {
// 进行判断,当数据发生改变时,Component重新渲染
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
this.updateState(nextProps)
return true
componentDidMount() {
// 改变Component的state
this.store.subscribe(() = {
this.setState({
storeState: this.store.getState()
render() {
// 生成包裹组件Connect
&WrappedComponent {...this.nextState} /&
Connect.contextTypes = {
store: storeShape
文中很多Redux的概念都是进行了简单的介绍,更多详细的介绍可以参考,GitHub地址:
每篇文章的结尾都会有一些简单的,帮助理解文章中介绍的内容。
文中结合三张图片介绍了Redux中的一些核心概念,以及React和Redux之间通过react-redux这个库进行交互。
更多详细的内容,已经整理到了GitHub上了(),通过这些介绍以及demo的运行结果,一定能对Redux有一个比较基本的认识。
阅读(...) 评论()Redux入门示例-TodoList - dataman - 博客园
前端技术真是日新月异,搞完 React 不搭配个数据流都不好意思了。满怀期待的心去翻了翻 flux,简直被官方那意识流的文档折服了,真是又臭又长还是我智商问题??转战 redux ,越看越有意思,跟着文档做了个 TodoList 的入门小例子。
废话不多说,先贴上文章用到例子的源码&redux 的 Github 仓库&还有个中文的 gitbook 翻译文档&
随着spa(不是SPA,是单页应用)的发展,以 react 来说,组件化和状态机的思想真是解放了烦恼的 dom 操作,一切都为状态。state 来操纵 views 的变化。然而,因为页面的组件化,导致每个组件都必须维护自身的一套状态,对于小型应用还好。但是对于比较大的应用来说,过多的状态显得错综复杂,到最后难以维护,很难清晰地组织所有的状态,在多人开发中也是如此,导致经常会出现一些不明所以的变化,越到后面调试上也是越麻烦,很多时候 state 的变化已经不受控制。对于组件间通行、服务端渲染、路由跳转、更新调试,我们很需要一套机制来清晰的组织整个应用的状态,redux 应然而生,这种数据流的思想真是了不起。
state 根对象的结构
在 react 中,我们尽量会把状态放在顶层的组件,在顶层组件使用 redux 或者 router。这就把组件分为了两种:容器组件和展示组件。容器组件:和 redux 和 router 交互,维护一套状态和触发 action。展示组件:展示组件是在容器组件的内部,他们不维护状态,所有数据通过 props 传给他们,所有操作也是通过回调完成。这样,我们整套应用的架构就显得清晰了。
redux 分为三大部分,store , action ,reducer 。
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。或者这么说 store 的指责有这些:
维护整个应用的 state
提供 getState() 方法获取 state;
提供 dispatch(action) 方法更新 state;
通过 subscribe(listener) 注册监听器。
这么解释一下,整个应用的 state 都储存在 store 中,容器组件可以从 store 中获取所需要的状态。容器组件同时也可以发送给 store 一个 action,告诉他改变某个状态的值,所以说容器组件只要发送一个指令,就可以叫 store 去 setState,然后 store 的 state 改变,回过来容器组件获取到的 state 改变,导致 views 的更新。
action 可以理解为一种指令,store 数据的唯一由来就是 action,action 是一个对象,它需要至少一个元素,type,type 是这个指令的唯一标识,其它元素是传送这个指令的 state 值
type: ACTION_TYPE,
text: &content&,}
这个指令由组件触发,然后传到 reducer。
action 只是说明了要去做什么,和做这件事情需要的参数值。具体去改变 store 中的 state 是由 reducer 来做的。reducer 其实是一个包含 switch 的函数,前面不是说组件触发的 action 会传递到 reducer,reducer 接收这个参数 action,他通过 switch(action.type) 然后做不同操作,前面说了,这个 type 是指令的标识,reducer 根据这个标识来作出不同的操作。这个操作是什么呢?reducer 还接收另一个参数 state,这个是旧的 state。从 action 里面还可以获取到做这个操作需要的 参数值。这个操作其实就是对原有的 state 和 从 action 中的到的值,来进行操作(结合,删除,&)然后返回一个 新的 state 到 store。
把前面的语言组织一下,整个操作的数据流其实是这样的:
store 把整个应用的 state,getState(),dispatch(),subscribe() 传给顶层容器组件;
容器组件和三个部分交互:reducer 得到容器组件传来的 action 之后,根据 action.type 这个参数执行不同操作,他还会接收到 store 里面的原 state,然后把原 state 和 action 对象里面的其它参数进行操作,然后 return 一个新的对象。
内部的展示组件:容器把状态分发给各个组件,把 dispatch(操作数据的函数)以回调的形式分发给各个组件;
action:容器获取 action;
reducer:容器可以调用 dispatch(action),这个上面说了,会以回调的形式给下面的子组件,这样就可以根据不同的用户操作,调用不同的 dispatch(action),执行了这个函数之后,就把 action 传给 reducer,然后看 reducer;
reducer return 一个新的对象到 store,store 根据这个新对象,更新应用状态。
----一个循环 ?
Redux 和 React 之间没有关系,他们并补互相依赖,但是 Redux 和 React 搭配起来简直完美。我们可以通过 react-redux 这个库把他们绑定起来
npm install
react-redux 提供两个东西 Provider 和 connect。
这个 Provider 其实就是一个中间件,他是在原有 App Container 上面再包一层,他的作用就是接收 store 里面的 store 作为 props,将store放在context里,给下面的connect用的。
这个组件才是真正连接 Redux 和 React,他包在我们的容器组件的外一层,他接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式床给我们的容器组件。
实战 TodoList
这个项目使用 webpack 来构建,想要了解 webpack 的配置可以看我的其它两篇文章:;.
.├── app
这里,我们只关注我们的 app 开发目录。
index.js 入口文件
import React from 'react';import { render } from 'react-dom';import { Provider } from 'react-redux';import App from './containers/App';import configureStore from './stores/configureStore';const store = configureStore();render(
这里我们从 react-redux 中获取了一个 Provider 组件,我们把它渲染到应用的最外层。他需要一个属性 store ,他把这个 store 放在context里,给App(connect)用。
app/stores.configureStore.js
import { createStore } from 'redux';import rootReducer from '../reducers';export default function configureStore(initialState) {
const store = createStore(rootReducer, initialState);
if (module.hot) {
module.hot.accept('../reducers', () =& {
const nextReducer = require('../reducers');
store.replaceReducer(nextReducer);
他从 redux 拿到 createStore 这个函数,再获取到 rootReducer ;createStore 函数接收两个参数,(reducer, [initialState]),reducer 毋庸置疑,他需要从 store 获取 state,以及连接到 reducer 交互。initialState 是可以自定义的一个初始化 state,可选参数。module.hot这个可以不用管,这是 webpack 热加载的处理,你也可以不要他。
containers/App.jsx
import React, { Component, PropTypes } from 'react';import { connect } from 'react-redux';import {
completeTodo,
setVisibilityFilter,
VisibilityFilters} from '../actions';import AddTodo from '../components/AddTodo';import TodoList from '../components/TodoList';import Footer from '../components/Footer';class App extends Component {
render() {
const { dispatch, visibleTodos, visibilityFilter } = this.
他从 react-redux 获取 connect 连接组件,通过&connect(select)(App)&连接 store 和 App 容器组件。select 是一个函数,他能接收到一个 state 参数,这个就是 store 里面的 state,然后通过这个函数的处理,返回一个对象,把对象里面的参数以属性传送给 App,以及附带一个 dispatch。所以在 App 里面可以:
const { dispatch, visibleTodos, visibilityFilter } = this.
所以 App 通过 connect 的到 state 和 dispatch,把 state 传递给子组件。dispatch 这个函数可以接收一个 action 参数,然后就会执行 reducer 里面的操作。比如:
dispatch(addTodo(text))
addTodo(text),这个函数是在 action 里面的到的,可以看 action 的代码,他其实返回一个 action 对象,所以其实就是dispatch(action)&。
app/actions/index.js
export const ADD_TODO = 'ADD_TODO';export const COMPLETE_TODO = 'COMPLETE_TODO';export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';export const VisibilityFilters = {
SHOW_ALL: 'SHOW_ALL',
SHOW_COMPLETED: 'SHOW_COMPLETED',
SHOW_ACTIVE: 'SHOW_ACTIVE',};export function addTodo(text) {
type: ADD_TODO,
};}export function completeTodo(index) {
type: COMPLETE_TODO,
};}export function setVisibilityFilter(filter) {
type: SET_VISIBILITY_FILTER,
在声明每一个返回 action 函数的时候,我们需要在头部声明这个 action 的 type,以便好组织管理。每个函数都会返回一个 action 对象,所以在 容器组件里面 调用
dispatch(addTodo(text))
就是调用dispatch(action)&。
app/reducers/visibilityFilter.js
SET_VISIBILITY_FILTER,
VisibilityFilters} from '../actions';const { SHOW_ALL } = VisibilityFfunction visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.
}}export default visibilityF
这里我们从 actions 获得各个 type 的参数,以便和 action 做好映射对应。整个函数其实就是执行 switch,根据不同的 action.type,返回不同的对象状态。但是如果我们需要 type 很多,比如除了 visibilityFilter,还有 todos,难道要写一个长长的switch,当然不。redux 提供一个 combineReducers 辅助函数,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore。我们把不同的 reducer 放在不同文件下。app/reducers/todo.js
COMPLETE_TODO} from '../actions';function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
text: action.text,
completed: false
case COMPLETE_TODO:
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
...state.slice(action.index + 1)
return state
然后通过一个 index.js 把他们合并。app/reducers/index.js
import { combineReducers } from 'redux';import todos from './todos';import visibilityFilter from './visibilityFilter';const rootReducer = combineReducers({
visibilityFilter});export default rootR
app/components/AddTodo/index.jsx
import React, { Component, PropTypes } from 'react';import { findDOMNode } from 'react-dom';export default class AddTodo extends Component {
render() {
&input type='text' ref='input' /&
&button onClick={ e =& this.handleClick(e) }&
handleClick(e) {
const inputNode = findDOMNode(this.refs.input);
const text = inputNode.value.trim();
this.props.onAddClick(text);
inputNode.value = '';
}}AddTodo.propTypes = {
onAddClick: PropTypes.func.isRequired};
app/components/Todo/index.jsx
import React, { Component, PropTypes } from 'react';export default class Todo extends Component {
render() {
const { onClick, completed, text } = this.
onClick={onClick}
textDecoration: completed ? 'line-through' : 'none',
cursor: completed ? 'default' : 'pointer'
}}Todo.propTypes = {
onClick: PropTypes.func.isRequired,
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired};
app/components/TodoList/index.jsx
import React, { Component, PropTypes } from 'react';import Todo from '../Todo';export default class TodoList extends Component {
render() {
this.props.todos.map((todo, index) =&
onClick={() =& this.props.onTodoClick(index)}
key={index}
}}TodoList.propTypes = {
onTodoClick: PropTypes.func.isRequired,
todos: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired
}).isRequired).isRequired};
app/components/Footer/index.jsx
import React, { Component, PropTypes } from 'react';export default class Footer extends Component {
renderFilter(filter, name) {
if(filter == this.props.filter) {
onClick={e =& {
e.preventDefault();
this.props.onFilterChange(filter);
render() {
{this.renderFilter('SHOW_ALL', 'All')}
{this.renderFilter('SHOW_COMPLETED', 'Completed')}
{this.renderFilter('SHOW_ACTIVE', 'Active')}
}}Footer.propTypes = {
onFilterChange: PropTypes.func.isRequired,
filter: PropTypes.oneOf([
'SHOW_ALL',
'SHOW_COMPLETED',
'SHOW_ACTIVE'
]).isRequired};
可以看出,所有的展示组件需要的 state 和 数据,都从属性中获取的,所有的操作,都是通过容器组件给的回调函数来操作的。他们尽可能地不拥有自己的状态,做无状态组件。
关于 redux 的用法,这只是基础入门的部分,还有的多的搞基操作,比如异步数据流、Middleware、和 router 配合。
随笔 - 117

我要回帖

更多关于 react redux connect 的文章

 

随机推荐