从0开始的Redux旅程(一)

前置知识点

  • 深拷贝与浅拷贝
  • FLUX架构

数据库模型

无论是MVC,MVVM,还是现如今的Flux,最强调的一点就是模块化的分离解耦.
因为整套系统是围绕数据运作的,所以

  • 表现是基于数据而来: 数据库的内容决定了展示的页面
  • 功能是基于数据而实现: 功能是在数据之上做修改

最终的结果就是,:

  • 数据(store)决定了展示(view)
  • 指令(action)改变了数据(store)
  • 展示(view)绑定了指令(action)

而具体是选择mvc, mvvm, 还是flux完全是基于那一部分东西多而决定的, 核心的理念都是相同的.

优先数据

界面归根结底是为了展现数据, 所以优先设计好数据模型. 再设计对这些数据模型所能实现的功能. 最后将这些功能附加到界面上.

Redux初体验

第一步总是做需求分析, 还是先做个todo

需求分析

  • 界面可以展现一个todolist
  • 有个按钮可以增加todolist的内容, 增加的todo默认是未完成
  • 每条todo后面会有一个按钮可以删除该条todo
  • 每条todo后面会有一个按钮可以完成该条todo
  • todolist下面有三个按钮, 分别可以展示所有todolist, 展示完成的todolist, 展示未完成的todolist

数据模型(store)设计

  • 数据是一个简单对象
  • 数据模型就是一个精简版的数据库
  • 数组总是很好的选择
{
  displayMode: // mode类型在我们公司的产品里一般是存放在域表里, 由ID指定.
  todoList: [
    {
       text:  //  todo的内容
       status:  // 状态, 如果需要的话可以把status放域表, 或者直接赋值true / false
  ]
}

动作指令(action)设计

  • 动作指令就是对数据模型操作的一串指令
  • 动作指令是一个对象
  • 这个对象必须包含type属性
{type:'ADD_TODO',payload:'Eating'}
{type:'DEL_TODO',payload:1}
{type:'TOGGLE',payload:2}
{type:'CHANGE_DISPLAY_MODE',payload:1}

其实就像是一堆机器伪代码

方法服务(reducer)设计

  • 后端的常见思路就是将对数据库操作的SQL写成一个个数据库服务.
  • Redux里就是写reducer
  • reducer就是一个函数,接受两个参数,一个是state,一个是action
  • status就是当前的数据模型的一部分,比如如果我们动作是操作数据模型中的displayMode部分,那么我们就设计一个displayModeReducer,接受当前的displayMode的值,再接受一个action作为执行参数.
  • action就是指令参数,传入的就是action
  • 一个reducer只返回state的一部分,比如你对displayMode做调整,就只返回displayMode的值就行了,如果你对todoList做调整,那么就返回一个todoList的数组就好了.
const displayModeReducer = function(state=0,action){
//执行动作
  return state
}
const todoListReducer = function(state=0,action){
//执行动作
  return state
}

合并服务(combineReducers)

  • 其实上边的动作都是纯原生js写的. 到这步才真正是Redux的API部分
  • 合并服务的目的是将所有Reducer合并进一个Reducers池中, 因为每个reducer只返回state的一部分, 所以将所有reducer拼起来必然是一个完整的state
  • 整合reducer的顺序按照store的结构顺序来就好了
import { combineReducers } from 'Redux';
const reducers = combineReducers({
    displayMode: displayModeReducer
    todoList: todoListReducer
}
)

生成数据模型(store)

  • 这步也是Redux的API
  • createStore需要两个蚕食,一个是合并后的服务,一个是初始的state
  • 生成的store带有getState()方法可以获取当前state
  • subscribe()方法可以监听传来的指令,然后执行回调
  • dispatch()方法可以对store执行指令
import { createStore } from 'Redux'
const store = createStore(reducers,{})

此时其实可以进行简单测试了

store.subscriber(()=>{console.log('Listen to State Change) , store.getState()})
//这样如果store监听到了指令的话,就会执行回调,返回store.getState().
//可以尝试发一串指令过去看看会得到什么,比如
store.dispatch({type: "CHANGE_DISPLAY_MODE", payload: 1})
store.dispatch({type: "CHANGE_DISPLAY_MODE", payload: 2})
store.dispatch({type: "CHANGE_DISPLAY_MODE", payload: 3})
store.dispatch({type: "ADD_TODO", payload: "HAPPY"})
store.dispatch({type: "ADD_TODO", payload: "EATING"})
store.dispatch({type: "ADD_TODO", payload: "WASHING"})
store.dispatch({type: "DEL_TODO", payload: 1})
store.dispatch({type: "TOGGLE", payload: 1})
//反正什么也得不到啦只会得到undefine,因为reducer没有正常返回,只返回了一堆空state
//这样的话就可以继续去完善reducer了

完善reducer

  • reducer的作用就是在收到指令action后,会重新返回一个新的state, 因为state的变化,那么界面也会相应变化.
  • 在reducer内主要不要对原始state进行突变(mutant), state部分是引用类型的值, 突变就会导致执行指令前后的state指向的实际对象被改变为相同的值, 这样会产生很多不好的影响比如无法做日志.
  • 现阶段好用的创建一个新的对象的方法, 可以用ES6的Object.assign方法, 结合ES6的展开运算符. 或者用一些其他库比如lodash或者jquery甚至immutable.js
  • 这部分建议多研究些方法, 看看lodash源码或者jq源码, ES6现在已经有许多很好用的原生对象API了, 数组更是能玩出花. 就不赘述了.
import { combineReducers } from 'redux'
const displayModeReducer = function (state = 0, action) {
    switch (action.type) {
        case "CHANGE_DISPLAY_MODE": {
            return action.payload;
        }
        default: {
            return state;
        }
    }
}
> 
const todoListReducer = function (state = [], action) {
    switch (action.type) {
        case "ADD_TODO": {
            return [...state, {text: action.payload, status: false}];
        }
        case "DEL_TODO": {
            return [...state.slice(0, action.payload), ...state.slice(action.payload + 1)]
        }
        case "TOGGLE": {
            return [...state.slice(0, action.payload),
                Object.assign({}, state[action.payload], {status: !state[action.payload][state]}),
                ...state.slice(action.payload + 1)]
        }
        default: {
            return state;
        }
    }
}

用函数创建action

刚才可以看到所有action都是手动打的, 比较麻烦, 可以考虑把生成指令组合成一些方法, 自动生成action对象.

const addTodo = (text) => ({
        type:"ADD_TODO",
        payload:text
    })
> 
const delTodo = (index) => ({
    type:"DEL_TODO",
    payload:index
})
> 
const changeDisplayMode = (modeId) => ({
    type:"CHANGE_DISPLAY_MODE",
    payload:modeId
})
> 
const toggle = (index) => ({
    type:"TOGGLE",
    payload:index
})

小结

到这一步, Redux的数据处理逻辑部分都已经完全实现了, 总共就用了量个API, createStore用来创建store, combineReducers用来合并所有的reducer. 可以说是相当简练了.

  • 设计数据模型, 确定好state的结构
  • 解剖state, 将每一段state的属性做成reducer, 每个reducer里加入处理逻辑
  • 用combineReducers将所有reducer合并成一个reducer
  • 用createStore将reducer制作成store
  • 设计指令模型, 将指令对象用函数生成
  • 此时就可以用store.subscribe()来监听指令了, 用store.dispatch()来发送指令.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容