资讯专栏INFORMATION COLUMN

Redux之旅-2

liangzai_cool / 3046人阅读

摘要:之旅时间作者三月懒驴入门配置文章链接之旅链接前言上一篇文章,很简单的用代码来说明了,,,各自的意义和相互的联系以及在实际开发的应用。分割你的,使每一个更有意义,之后再合并回来。分割和合并和不同。的只有一个只有一个就意味着只有一个。

Redux之旅-2

时间:2016.4.22-11:24
作者:三月懒驴
入门配置文章:链接
Redux之旅-1:链接

1. 前言

上一篇文章,很简单的用代码来说明了State,Action,Reducer,Store各自的意义和相互的联系以及在实际开发的应用。但是在现实开发环境用,我们的需求不仅仅上一篇文章那么简单的。为了应付这些复杂的开发环境,我们还需要用到以下这些东西:

Action Creator / bindActionCreators:动态去生成Action。

combineReducers:分割你的reducers,使每一个reducer更有意义,之后再合并回来。

applyMiddleware / createStoreWithMiddleware:往store里面添加中间件。使得它的功能更加强大。

很明显,我们将要学习的这三个功能,对应回上一篇文章的Action,reducer,store。你可以认为这是它们各自的一些扩展。

2. 新的需求

在上一篇文章我们的需求很简单。就是一个按钮,点击就让数字递增,那么今天为了学习新的东西,我们就增加一些新的需求。我们需求加两个按钮,一个按钮就是点击数字是+2,一个按钮是切换数字颜色。那么为了更方便我们的开发,我们的开发目录也应该修改一下。

主要写代码的还是在app这个文件夹里面,里面的目录分布

component -->放置组件的

index.js

redux -->放置redux

action -->action相关的

types.js

creator.js

reducer -->reducer相关的

rootReducer.js

increaseReducer.js --> 处理增加按钮用的

themeReducer.js --> 处理切换主题按钮用的

store -->store相关的

store.js

index.js -->把组件和store connect在一起生成一个新组件

main.js -->程序入口

3. Action Creator 3.1 为什么需要Creator

在Redux之旅-1里面,我们创建了一个很简单的例子:点击按钮递增。那么在更多的时候,我们的开发需求是很复杂的。那么增加一个点击就+2的按钮。这时候我们要怎么做?
还记得我们上次定义的Action是这样的:

let IncreaseAction = {type:"increase"}

其中字符串increase的意思就是增加,那么我们现在的需求里面,一个点击+2的按钮,也符合increase这个意思。这时候的Action就不能像之前那样,直接写死。因为写死了就没办法让reducer知道,这个Action是+1还是+2了!而需要引入一个新的概念:Action Creator

let IncreaseAction = (num = 1)=>{
 return{
     type:"increaseAction",
     num  //看注1
 }
}

注1:这里用到了ES6的新语法,增强字面量。具体看文章最后的注释

上面就是一个Action Creator,听起来很高大上的英文名词,其实就是一个帮我们返回Action的函数。那还记得Action的本质其实是什么吗?一个我们规定最了低限度要带着type属性的对象。那么其实就很简单了。Creator每次帮我们生成type都是increaseAction,但num不同的Action出来。这样,reducer就能分辨出我们的这个Action要+1还是+2

3.2 代码实现

文件位置: app/redux/action/types.js

//为了更加直观,我们把每个Action的type属性的值额外用一个文件去描述
export const INCREASE = "increase"  //增加数字的
export const THEME = "theme"  //切换主题的

文件位置: app/redux/action/creator.js

import * as types from "./types"

export let increaseAction = (num = 1)=>{
  return {
    type:types.INCREASE,
    num
  }
}

export let themeAction = ()=>{
  return {
    type:types.THEME,
  }
}

OK!上面的代码中,我还顺便把切换主题的Action也写了,虽然它不需要传入参数去处理,但是为了以后的拓展性,用Action Creator总比用写死了的Action更佳,毕竟产品经理要改需求,谁也挡不住。

4. combineReducers 4.1 分割和合并

和Flux不同。Redux的store只有一个!只有一个store就意味着只有一个state。那么我们设计state的时候就很会纠结了。像现在这样子:

let state = {
    count:0,  //增加数字
    theme:"#ffffff"  //主题颜色
}

这并不是一个理想的state。一个理想的state应该要设计得很纯粹。不应该把无关得两个东西交错在一起。因为,我们需要分割开我们的reducer。每个不同的reducer下面仅仅处理自己拥有的state.

let CountState = {
    count:0,  //增加数字
}
let ThemeState = {
    theme:"#ffffff"  //主题颜色
}

这样的话,我们的state就可以设计得很小,并且很纯粹。而作为汇总,我们会用combineReducers把这些reducers合并回来。实际上state还是一大块,但是在reducer的角度来看,每个reducer都指示一小块。

4.2 代码实现

文件位置: app/redux/reducer/increaseReducer.js

//处理数字增加的reducer
import * as types from "../action/types"

let reducer = (state={count:0},action)=>{
    let count = state.count
    switch(action.type){
        case types.INCREASE:
            //注意这里使用的action.num,明白是从哪里来的吗?
            return {count:count+action.num}
            break
        default:
            return state
    }
}
export default reducer

文件位置: app/redux/reducer/themeReducer.js

//处理主题的reducer
import * as types from "../action/types"

const writeColor = "#ffffff"
const grayColor = "#cccccc"
let reducer = (state={color:writeColor},action)=>{
    let count = state.count
    switch(action.type){
        case types.THEME:
            if(state.color == writeColor){
              return {color:grayColor}
            }
            else {
              return {color:writeColor}
            }
            break
        default:
            return state
    }
}
export default reducer

文件位置: app/redux/reducer/rootReducer.js

//合并两个reducer
import { combineReducers } from "redux"
import Increase from "./increaseReducer"
import Theme from "./themeReducer"

const rootReducer = combineReducers({
    Increase,
    Theme
})

export default rootReducer
5. Middleware 5.1 什么叫做中间件

在这里我并不打算深入去描述中间件这种概念,如果你是做node开发的话,又刚好用上了KOA的话,你会对这个东西很熟识。那么这里我简单的介绍一下什么是中间件。

你可能认为它是一个使用包含自定义功能的(可以让你包装 store 的 dispatch 方法来达到你想要的功能),用来扩展 Redux 是一种方式。

在这里,有两个中间件是推荐使用的。

//用来打log的,开发时候用很方便
npm install --save-dev redux-logger  
//这个会在异步Action的时候用到,这篇文章没有到,不细说。
npm install --save redux-thunk

注2:thunk,推荐阅读阮一峰老师的Thunk 函数的含义和用法

5.2 代码实现

文件位置: app/redux/store/store.js

"use strick"
import {createStore,applyMiddleware} from "redux"
import createLogger from "redux-logger"
import rootReducer from "../reducer/rootReducer"
/*
    以前创建store的方式:
    let store = createStore(reducers)
*/
let createStoreWithMiddleware = applyMiddleware(
  createLogger(),
)(createStore)
let store = createStoreWithMiddleware(rootReducer)

export default store
6. 连接组件和redux

这里面和以前的差不多,但又有一些细节上的东西,我们需要注意的

文件位置: app/redux/index.js

"use strict"

import React from "react"
//注意这里引入:bindActionCreators
import { bindActionCreators } from "redux"
import { Provider,connect } from "react-redux"

//这里引入了组件
import Index from "../component/index"

//引入了action creator 和 store。为啥没有引入reducer?
//因为reducer在上面创建store的时候已经用到了
import * as actions from "./action/creator"
import store from "./store/store"

let {Component} = React

/*
    mapStateToProps里面需要注意的是,由于我们的reducer是合并起来的,因此我们的state也是几个state拼起来。至于是哪几个state拼起来?
    可以看回去rootReducer.js里面combineReducers的时候,里面的对象名字就是这里state的名字。
    当然这里的return可以写成:return {state}也没所谓。但是为了大家能认清这个state里面有什么东西,这里写的稍微复杂一点
*/
let mapStateToProps = (state) =>{
    //return {state}
    return {
        reduxState:{
            Increase:state.Increase,
            Theme:state.Theme,
        }
    }
}
/*
    mapDispatchToProps里面用到了bindActionCreators。关于bindActionCreators的作用看下面注释3
*/
let mapDispatchToProps = (dispatch) =>{
    return{
        reduxActions:bindActionCreators(actions,dispatch)
    }
}
let Content = connect(mapStateToProps,mapDispatchToProps)(Index)



class App extends Component{
    render(){
        return 
    }
}

export default App

注3: bindActionCreators(actionCreators, dispatch):是把 action creators 转成拥有同名 keys 的对象,而使用 dispatch 把每个 action creator 包围起来,这样可以直接调用它们。

7. 组件开发

关于redux的开发在上面已经完成了,现在进入的是组件的开发,这里面更多的是满足例子而写的。没有太多的现实开发价值。但是我们可以在这里面很好的观察,我们写好的程序是怎样工作的。

文件位置: app/component/index.js

"use strict"

import React from "react"
let {Component}  = React
class Index extends Component{
    constructor(props){
        super(props)
    }
    //点击增加按钮事件
    _addHandle(num){
    /*
    这里面可以想一下increaseAction的名字是怎么来的,同样下面主题切换按钮事件的themeAction又是怎么来的,代码之后为你揭秘。
    */
        let {increaseAction} = this.props.reduxActions
        increaseAction(num)
    }
    //主题切换按钮事件
    _ThemeHandle(){
        let { themeAction } = this.props.reduxActions
        themeAction()
    }
    render(){
        //这里面输出props看看里面有什么东西
        //console.log(this.props)
        let { reduxState } = this.props
        return (
            
{reduxState.Increase.count}
切换主题
{this._addHandle(1)}}>+1
{this._addHandle(2)}}>+2
) } } //样式定义,不用细看 const styles = { circle:{ width:"400px", height:"400px", position:"absolute", left:"50%", top:"50%", margin:"-200px 0 0 -200px", borderRadius:"50px", fontSize:"60px", color:"#545454", backgroundColor:"#ececec", lineHeight:"100px", textAlign:"center", }, btnAddOne:{ width:"100px", height:"50px", lineHeight:"50px", backgroundColor:"#fcfcfc", fontSize:"20px", position:"absolute", left:"40px", bottom:"10px", cursor:"pointer", }, btnAddTwo:{ width:"100px", height:"50px", lineHeight:"50px", backgroundColor:"#fcfcfc", fontSize:"20px", position:"absolute", right:"40px", bottom:"10px", cursor:"pointer", }, btnTheme:{ width:"80%", height:"50px", lineHeight:"50px", backgroundColor:"#fcfcfc", fontSize:"20px", position:"absolute", right:"10%", bottom:"100px", cursor:"pointer", } } export default Index

需要注意:在redux里面action/creator/reducer/store各种定义太多了。有时候你很难找到这个东西的名称是哪里定义过来的感觉。输出组件的props的话,我们得到这么一个东西

{
    reduxAction:{
        increaseAction:fn(),
        themeAction:fn(),
    },
    reduxState:{
      Increase:count,
      Theme:color,
    }
}

reduxAction:来自redux/index.js里面,我们mapDispatchToProps的时候return 的一个对象时候自己定义的一个对象名字

increaseAction:fn()/themeAction:fn():因为bindActionCreators的转化造成的和creator的同名函数。因此这两个函数的名称定义出自redux/action/creator.js

reduxState:来自redux/index.js里面,我们mapStateToProps的时候return 的一个对象时候自己定义的一个对象名字

Increase/Theme 也是在mapStateToProps里面自己定义的。

这里顺便贴出入口文件

文件位置: app/main.js

"use strict"
import "babel-polyfill"
import React from "react";
import { render } from "react-dom"

import App from "./redux/index";

render(
    ,
    document.getElementById("main")
);

如果没有做错,我们的程序能跑起来,如同下图一般

而控制台会在每次按钮之后,会如同下图一样

8. 总结

和上一次说明state/Action/reducer/store的各种比如不同,这次需要说的分别是Action/reducer/store的一些扩展,为了更好的写程序,这些扩展是必不可少的,但会给新手一种把程序切割得很零散从而无从下手得感觉。所以这次我更加偏重于说明,每一个扩展存在得意义以及代码得实现,希望大家能看懂。

9.一些ES6的小知识

在3.1的注1的时候,我们说了一个ES6的新特性:字面量增强
ES6里面我们定义一个对象的时候

let c = "abc"
let obj = {
   a,   //这个叫做键名简写
   b(){   
       //这个是函数定义的简写
       .... 
   },
   [c]:12   // 这个是自定义键值写法,一个很有趣的语法糖
}

等于号后面我们叫做 字面量
以上代码等价于以下

let obj = {
   a:a,    
   b:function(){   
      ....
   },
   abc:12    
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79478.html

相关文章

  • Redux之旅-1

    摘要:我们约定,内使用一个字符串类型的字段来表示将要执行的动作。多数情况下,会被定义成字符串常量。要进去工厂加工产品,就得带上相应得钥匙,不同的钥匙对应工厂中上不同的生产线里面的函数,从而有不同的产出改变之后的 时间:2016.4.7-17:24作者:三月懒驴入门配置文章:链接 准备 在你的项目下面加入redux / react-redux npm install redux --s...

    hiyang 评论0 收藏0
  • MobX学习之旅

    摘要:一其实是一个比较轻便的可扩展的状态管理工具,是一个由以及一些其他团队的人共同维护的开源项目。当应用公共状态的组件在状态发生变化的时候,会自动完成与状态相关的所有事情,例如自动更新自动缓存数据,自动通知等。 一、MobX MobX其实是一个比较轻便的可扩展的状态管理工具,是一个由Facebook以及一些其他团队的人共同维护的开源项目。 当应用公共状态的组件在状态发生变化的时候,会自动完...

    刘福 评论0 收藏0
  • [译]看这些文章,足够你学好redux

    摘要:原文地址我想分享一些文章,来帮你学习的概念和架构在开始之前我们先来看这两篇文章,用代替和然后我们通过一个代码教程我翻译地址深入了解,然后看一看超级介绍完成你对的探索之旅现在是时候去学习和再往前走理解并且看一看关于的一切注尽量中文地址的我用的 原文地址 我想分享一些文章,来帮你学习redux的概念和架构 在开始redux之前我们先来看这两篇文章,用High Order Component...

    fengxiuping 评论0 收藏0
  • 我的源码阅读之路:redux源码剖析

    摘要:到月底了,小明的爸爸的单位发了工资总计块大洋,拿到工资之后第一件的事情就是上交,毫无疑问的,除非小明爸爸不要命了。当小明的爸爸收到这个通知之后,心的一块大石头也就放下来了。下面我们正式开始我们的源码阅读之旅。 前言 用过react的小伙伴对redux其实并不陌生,基本大多数的React应用用到它。一般大家用redux的时候基本都不会单独去使用它,而是配合react-redux一起去使用...

    CloudwiseAPM 评论0 收藏0
  • 滚蛋吧!constant 君

    摘要:引入,有效解决事件分发时,事件类型的一致性以及清晰逻辑性。其实,细心思考,不难发现,随着项目增大。目录将会随着数据处理事件迅速膨胀。大家一直维护着这个事件命名机制,身心疲惫有木有。其实,随着项目增大,独立出来的也会导致非常麻烦的维护问题。 作者:Jogis原文链接:https://github.com/yesvods/Blog/issues/4转载请注明原文链接以及作者信息 前言 事情...

    huangjinnan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<