redux快速学习指南

Flux ??Redux是Flux思想的另一种实现方式。Flux是和React同时面世的。React用来替代jQuery,Flux用来替换Backbone.js等MVC框架。在MVC的世界里,React相当于V(view)的部分,只涉及页面的渲染。一旦涉及应用的数据管理部分,还是交给Model和Controller。不过,Flux并不是一个MVC框架,它用一种新的思路来管理数据。
【MVC】
MVC是业界广泛接受的一种前端应用框架类型,这种框架把应用分为三个部分:
Model(模型) 负责管理数据,大部分业务逻辑应该放在Model中。
View(视图) 负责渲染用户页面,应该避免在View中涉及业务逻辑。
Controller(控制器) 负责接受用户输入,根据用户输入调用相应的Model部分逻辑,把产生的数据结果交给View部分,让View渲染出必要的输出。
MVC框架提出的数据流很理想,用户请求先到达Controller,由Controller调用Model获得数据,然后把数据交给View。但是,在实际框架实现中,总是允许View和Model直接通信。
【Flux】
Facebook用Flux框架来替代原有的MVC框架,这种框架包含四个部分:
Dispatcher 负责动作分发,维持Store之间的依赖关系
Store 负责存储数据和处理数据相关逻辑
Action 驱动Dispatcher的javascript对象
View 视图负责显示用户界面
如果非要把Flux和MVC做一个对比。那么,Flux的Dispatcher相当于MVC的Controller,Flux的store相当于MVC的model,Flux的View对应于MVC的ViewAction对应给MVC框架的用户请求。
【优势】
在Flux中,Store只有get方法,没有set方法,根本不可能直接去修改其内部状态,View只能通过get方法获取Store的状态,无法直接去修改状态,如果View想要修改Store的状态,只能派发一个action对象给Dispatcher。
【不足】
1、Store之间依赖关系
在Flux的体系中,如果两个Store之间有逻辑依赖关系,就必须用上Dispatcher的waitFor函数。
2、难以进行服务器端渲染
3、Store混杂了逻辑和状态
Redux ??Redux的含义是Reducer+Flux。Reducer是一个计算机科学中的通用概念。以Javascript为例,数组类型有reduce函数,接受的参数是一个reducer,reducer做的事情就是把数组所有元素依次做规约,对每个元素都调用一次参数reducer,通过reducer函数完成规约所有元素的功能。
Flux的基本原则是单向数据流,Redux在此基础上强调三个基本原则:
1、唯一数据源
2、保持状态只读
3、数据改变只通过纯函数完成
redux专注于状态管理,如果你的应用有以下场景,可以考虑使用 Redux。

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态
redux快速学习指南
文章图片
核心概念包括:storestateactionreducer
【store】
store是保存数据的地方,redux提供createStore函数来生成 Store。函数参数是后面要介绍的reducer。整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。
import { createStore } from 'redux' const store = createStore(reducer)

【state】
statestore的某个时刻的快照,可以通过store.getState()取得当前时刻的statestate是只读的,唯一改变state的方法就是触发action。
const state = store.getState()

【action】
action用来改变stateaction是一个对象,其中的type属性是必须的,其他的属性一般用来设置改变state需要的数据。state的变化会导致view的变化,但是用户接触不到state,只能接触到view。所以,state的变化必须是view导致的。action就是view发出的通知,表示state应该要发生变化了。
const action = { type: 'ADD_ONE', num: 1 }

view要发送多少种消息,就会有多少种action。如果都手写,会很麻烦,可以定义一个函数来生成action,这个函数就叫action Creator
const ADD_TODO ='添加 TODO' function addTodo (text) { return { type : ADD_TODO, text } } const action = addTodo('学习Redux')

store.dispatch()是发出action的唯一方法
const action = { type: 'ADD_ONE', num: 1 } store.dispatch(action)

【reducer】
reducer 是一个函数,它接受action和当前state作为参数,返回一个新的state
const reducer = (state = 10, action) => { switch (action.type) { case 'ADD_ONE': return state + action.num; default: return state; } };

store.dispatch发送过来一个新的actionstore就会自动调用reducer,得到新的state。
【combineReducers】
传入store时只能传入一个reducer,多个reducer需要进行合并。
let reducers = combineReducers ({ counter : counter, todo : todo })

combineReducers实现源码
export default function combineReducers(reducers) { return function (state={},action) { return Object.keys(reducers).reduce((newState,key) => { newState[key]=reducers[key](state[key],action); return newState; },{}); } }

【简单实例】
多余的概念不再介绍,下面用上面介绍的这四个核心概念实现一个简单的实例。
//第一步,创建action const addOne = { type: 'ADD', num: 1 } const addTwo = { type: 'ADD', num: 2 } const square = { type: 'SQUARE' }//第二步,创建reducer let math = (state = 10, action) => { switch (action.type) { case ADD: return state + action.num case SQUARE: return state * state default: return state } } //第三步,创建store import { createStore } from 'redux' const store = createStore(math)//第四步,测试,通过dispatch发出action,并通过getState()取得当前state值 console.log(store.getState()) //默认值为10store.dispatch(addOne) //发起'+1'的action console.log(store.getState()) //当前值为10+1=11store.dispatch(square) //发起'乘方'的action console.log(store.getState()) //当前值为11*11=121store.dispatch(addTwo) //发起'+2'的action console.log(store.getState()) //当前值为121+2=123

【redux目录】
1、一般地,将action.type设置为常量,这样在书写错误时,会得到报错提示。
// action/ActionTypes.js export const ADD = 'ADD' export const SQUARE = 'SQUARE'

??2、可以将addOne对象和addTwo对象整合成add函数的形式
// action/math.js import { ADD, SQUARE } from '../constants/ActionTypes' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE }

??3、根据action.type的分类来拆分reducer,最终通过combineReducers方法将拆分的reducer合并起来。上例中的action类型都是数字运算,无需拆分,只需进行如下变化
// reducer/math.js import { ADD, SQUARE } from '../constants/ActionTypes' const math = (state = 10, action) => { switch (action.type) { case ADD: return state + action.num case SQUARE: return state * state default: return state } } export default math

// reducer/index.js import { combineReducers } from 'redux' import math from './math' const rootReducer = combineReducers({ math }) export default rootReducer

??4、将store存储到store/index.js文件中
// store/index.js import { createStore } from 'redux' import rootReducer from '../reducer' export default createStore(rootReducer)

??5、最终,根路径下的index.js内容如下所示
import store from './store' import {add, square} from './action/math'console.log(store.getState()) //默认值为10store.dispatch(add(1)) //发起'+1'的action console.log(store.getState()) //当前值为10+1=11store.dispatch(square) //发起'乘方'的action console.log(store.getState()) //当前值为11*11=121store.dispatch(add(2)) //发起'+2'的action console.log(store.getState()) //当前值为121+2=123

最终目录路径如下所示

redux快速学习指南
文章图片
UI层 前面的示例中,只是redux的状态改变,下面利用UI层来建立viewstate的联系,将根目录下的index.js的内容更改如下。
import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square } from './action/math'ReactDOM.render({store.getState().math}
store.dispatch(add(1))} value="https://www.it610.com/article/+1" /> store.dispatch(add(2))} value="https://www.it610.com/article/+2" /> store.dispatch(square)} value="https://www.it610.com/article/乘方" /> , document.getElementById('root') )

虽然可以显示数字,但是点击按钮时,却不能重新渲染页面。
【store.subscribe()】
接下来介绍store.subscribe()方法了,该方法用来设置监听函数,一旦state发生变化,就自动执行这个函数。该方法的返回值是一个函数,调用store.unsubscribe()这个函数可以解除监听。
import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square } from './action/math'const render = () => ReactDOM.render(【redux快速学习指南】{store.getState().math}
store.dispatch(add(1))} value="https://www.it610.com/article/+1" /> store.dispatch(add(2))} value="https://www.it610.com/article/+2" /> store.dispatch(square)} value="https://www.it610.com/article/乘方" /> , document.getElementById('root') )render() store.subscribe(render)

    推荐阅读