转载

Redux basic tutorial

@(blog)

Redux basic tutorial

本文的读者为了解flux概念,熟悉react,了解es6语法的同学

redux 是最近很火的一个 flux 框架,短短的一个月现在已经有2900+的 star 了,watch之后每天收到几百封 pr 的邮件,废话就不多说了。

为什么要用 redux ,请看连接 The Evolution of Flux Frameworks 。

主要特点

  • Everything (Stores, Action Creators, configuration) is hot reloadable. —— 配合起 hotloader 应该特别爽,虽然现在用的是 browserify ,好处感觉并不明显。
  • store 中的数据不受限制,可以是 number object array 等等,废话,因为它的 store 只是简单的函数。
  • 提供 devtools ,监控 action 的触发以及 state 的变化。
  • 源码清晰简单,轻量级,根本不需要文档,直接看源码就行了….缺点就是如果看不懂源码,光看文档会觉得不够清晰。
  • api 很精简,不用记茫茫多的 api
  • every thing is simple function
  • connecterprovider 这两个东西用起来总觉得很繁琐,不那么优雅。

下面通过写的一个简单counter的例子 介绍 redux 的核心方法以及一些需要注意的地方。

  • 同步与异步两种actionCreator
  • middleware的使用
  • dispatch actions
  • 拿到并同步state

代码放在 https://github.com/yeatszhang/redux-tutorial , 需要安装gulp

代码是基于分支 v1.0.0-rc api略微有些区别,详情见 Breaking API changes for 1.0 。

actionCreator

actions creator 是用来生成 action 的函数,在默认情况下可以接受返回 object 或者 function 的函数,很多人学习flux的时候把action与actionCreator弄混淆….:

// 直接返回object actionCreators.addTodo = function(text) {   return {     type: types.ADD_TODO,     text   }; }  // 返回函数 actionCreators.incrementAsync = function() {   return (dispatch, getState) => {     // actionCreator中可以通过getState获得当前的state     console.log(getState());     // 异步action     setTimeout(() => {       dispatch({         type: INCREMENT_COUNTER2,       });     }, 1000);   }; };  

在没有使用任何 middleware 的情况下,只有这有两种 action 可以被 dispatch

app

在动态内容的最外层应该使用Provider进行包裹,provider接收store作为参数,注意children是一个 函数 并不是 reactElement

provider 将store作为context往子节点进行传递,并实现 store 的热替换。因此在provider内的组件其实可以不通过connect来拿到dispatch以及state,而直接通过context拿到store对象,不过作者不推荐这么做。

import React from 'react'; import { createStore, applyMiddleware, combineReducers } from 'redux'; // redux midlleware repositories import thunk from 'redux-thunk'; // 将 redux 与 react 相关的部分,如 connector provider 单独抽取出来 import { Provider } from 'react-redux'; import reducers from '../reducers'; import CounterApp from './CounterApp.js'; import logMiddleware from '../middleWares/logMiddleware.js';  const reducer = combineReducers(reducers); const createStoreWithMiddleware = applyMiddleware(thunk, logMiddleware)(createStore); const store = createStoreWithMiddleware(reducer); // 使用middleWare thunk, 如果没有自定义中间层的需求可以直接写 // const store = createStore(reducer);  class App extends React.Component {   render() {     return (       <Provider store={store}>         {() => <CounterApp />}       </Provider>     );   } } 

smart component

smart component拥有两个特点:

  1. 自动关联store中的state并自动re-render
  2. 可以通过dispatch来分发事件,从而触发store的更新

刚接触redux的同学肯定会觉得这个connect很难以理解。还是在代码里面说把。。。

/**  * Created by yichizhang on 15/7/26.  */  import React, { Component } from 'react'; import { bindActionCreators } from 'redux'; import { Connector } from 'react-redux'; import Counter from '../components/Counter'; import actionCreators1 from '../actionCreators/actionCreators1.js'; import actionCreators2 from '../actionCreators/actionCreators2.js';  // state 是各reducer中state的集合 function select(state) {   // 从各reducer中挑选出component需要监听的state   return {     counter1: state.reducer1.counter,     counter2: state.reducer2.counter,   }; }  export default class CounterApp extends Component {   // select函数的返回值会与dispatch组装程一个object作为参数   // 从这里看出connector就是帮忙拿到provider中store的dispatch方法以及挑选出需要使用的state   renderChild({ counter1, counter2, dispatch}) {     // 个人觉得这样使用action十分不方便,尤其是当组件只需要触发actions不需要监听store的变化的时候。我会偷懒通过context去拿到dispatch~~     const actions1 = bindActionCreators(actionCreators1, dispatch);     const actions2 = bindActionCreators(actionCreators2, dispatch);     const props = { ...actions1, ...actions2, counter1, counter2 };     // 所有的action以及state都会以props的形式提供给Counter,然后在Counter里面就可以为所欲为了~     return <Counter {...props} />;   }    render() {     return (       <Connector select={select}>         {this.renderChild}       </Connector>     );   } }  

reducer

redux认为程序员不需要去写store中的逻辑而只需要写明对state的处理逻辑就好:

old  sate => action  => new state 

这是一个完全同步的过程。reducer只需要声明初始状态以及state在接收到action之后的改变规则就可以了。

import React from 'react/addons'; import {INCREMENT_COUNTER1, DECREMENT_COUNTER1} from '../constants/actionsTypes.js'; const update = React.addons.update;  // state可以是任何类型 const initialState = {   counter: 0, };  // reducer只是一个简单的switch方法 export default function counter(state = initialState, action = null) {   switch (action.type) {     case INCREMENT_COUNTER1:       // 需要注意的是connector当select中的state发生变化时会做一个shallow equal的操作,       // 所以如果需要操作引用值的时候一定不能直接赋值,需要使用addon中的update或者immutable.js,知道看到这两个工具又不想继续学了..其实很简单       // 这样可以大大避免重复的render,从而提高性能       return update(state, {         counter: {           $set: state.counter + 1,         },       });     case DECREMENT_COUNTER1:       return update(state, {         counter: {           $set: state.counter - 1,         },       });     default:       return state;   } }  

middleWare

感兴趣的同学可以看看,一般来说默认的thunk就够用了。我在例子里加了个log的中间层

// 打印触发的action function logMiddleware() {   // 这里的next是下一个middleWare   return function(next) {     return function(action) {       // 打印此action并使用下一个middleWare处理该action       console.log(action);       next(action);     };   }; }  export default logMiddleware;  // 下面是默认的thunk middleWare  function thunkMiddleware(_ref) {   var dispatch = _ref.dispatch;   var getState = _ref.getState;    return function (next) {     return function (action) {       // 如果是函数则将dispatch与getState作为参数执行函数,否则交给写一个middleware处理       return typeof action === 'function' ? action(dispatch, getState) : next(action);     };   }; } 

结语

其实redux不明白的地方直接看源码更好,redux的代码量很小而且组织也很清晰,建议大家都去看,不过作者貌似函数式编程的思维很重,大量使用修饰器的语法,还有reduce~ 挺绕的~

之后会总结自己阅读redux源码的一些心得,以及各功能模块的实现原理~

正文到此结束
Loading...