Flux => Redux
上一篇文章中,提到了React中的Flux架构,尽管理解起来相对容易,但是随着项目体系的增加,需要实时地将容器组件(处理页面逻辑)与UI组件(负责页面渲染)分离,手动地来降低各个模块之间的耦合度。
而Redux的出现,解决了过于复杂地拆分,可以更高效地管理多个store,并且不需要对每个视图更新函数做绑定。
- Redux的设计思想
Web 应用是一个状态机,视图与状态是一一对应的。
所有的状态,保存在一个对象里面(唯一数据源)。
注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。
一、为什么要使用Redux
简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
- 需要使用Redux的项目
- 用户的使用方式复杂
- 不同身份的用户有不同的使用方式(比如普通用户和管理员)
- 多个用户之间可以协作
- 与服务器大量交互,或者使用了WebSocket
- View要从多个来源获取数据
- 从组件层面考虑是否需要Redux
- 个组件的状态,需要共享
- 某个状态需要在任何地方都可以拿到
- 一个组件需要改变全局状态
- 一个组件需要改变另一个组件的状态
- Redux使用的三大原则
- Single Source of Truth(唯一的数据源)
- State is read-only(状态是只读的)
- Changes are made with pure function(数据的改变必须通过纯函数完成)
二、快速上手
redux.png当组件要修改数据的时候,通过ActionCreators中的dispatch发送action给store,但是store的内部将action传递给了reducers,reducers进行了数据的更改,将新的state返回给store,由于store中的数据中响应式的,最后通过store通知view再次更新视图。
- 安装
cnpm i redux -S
- createStore函数,专门用来创建公共的内存空间store,将这里的数据渲染到页面上。
store是一个对象,里面有几个常用的函数:getState / dispatch / subscribe
参数:回调函数reducers
import {createStore} from "redux";
import reducers from "./reducers"
const store = createStore(reducers);
export default store;
- reducer.js
必须是一个纯函数(输入一定,输出也一定),函数中有两个参数:1. state 2. action;Redux为了防止报错,默认给了参数初始值 。
当前函数必须有一个默认的state
纯函数内部的state只允许读,不允许修改
不能调用系统 I/O 的API
当前函数必须要返回一个state,返回的state会替换原来的state
state = reduce(state , action)
//存储初始的数据
const defaultState = {
n:10
}
export default (state=defaultState,action)=>{
switch(action.type){
case "NUM_ADD":
var numState = JSON.parse(JSON.stringify(state));
numState.n++;
return numState;
}
return state
}
- App.js
import React, { Component } from 'react'
import store from "./store"
export default class App extends Component {
constructor() {
super();
this.state = store.getState();
store.subscribe(this.handleUpdate.bind(this))
}
render() {
let { n } = this.state;
return (
<div>
<h2>{n}</h2>
<button onClick={this.handleClick.bind(this)}>点击</button>
</div>
)
}
handleClick() {
var action = {
type: "NUM_ADD"
}
store.dispatch(action);
}
handleUpdate() {
this.setState(store.getState())
}
}
三、combineRedux
因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别多。简单概括,该方法用来合并多个reducers
- 注意
- 分离reducer的时候,每一个reducer维护的状态都应该不同
- 通过store.getState获取到的数据也是会按照reducers去划分的
- 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态
- 安装
cnpm i redux-devtools-extension -D
- 引入
import { createStore, combineReducers } from "redux"
import { composeWithDevTools } from "redux-devtools-extension";
- combineReducers合并多个reducers
import { createStore, combineReducers } from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
//combineReducers 合并多个reducers
import num from "./reducers/num"
import todo from "./reducers/todo"
const reducers = combineReducers({
num,
todo
})
const store = createStore(reducers, composeWithDevTools());
export default store;
四、Redux封装
- store/index.js
store中要返回一个对象,包含三个常用的方法getState/dispatch/subscribe
import { createStore, combineReducers } from "../redux/index"
import num from "./reducers/num"
import todo from "./reducers/todo"
const reducers = combineReducers({
num,
todo
})
const store = createStore(reducers);
//store应该是一个对象 getState dispatch subscribe
export default store;
- store/reducer/num.js
这里的state要有默认值defaultState,没有时为undefined(注意:不能赋值为null)
const defaultState = {
n: 10
}
export default (state = defaultState, action) => {
switch (action.type) {
case "NUM_ADD":
var numState = Object.assign({}, state);
numState.n++;
return numState;
}
return state;
}
- redux/index.js
上面的action中默认有一个初始值。
getState返回state值;
subscribe监听eventList中的函数;
dispatch接收action,传入state和action触发reducer处理逻辑
var initAction = { type: "@@/redux" }
export const createStore = (reducer) => {
let eventList = [];
let state = {};//默认为undefined
// 返回state
let getState = () => state;
// 监听eventList中的函数
let subscribe = (callback) => {
eventList.push(callback);
}
let dispatch = (action) => {
state = reducer(state, action);
eventList.forEach(cb => {
cb();
})
}
// dispatch第一次默认会调用
dispatch(initAction);
return {
getState,
subscribe,
dispatch,
}
//combineReducers的返回值是一个函数
export const combineReducers = (reducers)=>{
var newState = {};
return (state,action)=>{
for(var key in reducers){
newState[key] = reducers[key](state[key],action);
}
return newState;
}
}
}
网友评论