React:快速上手(4)——掌握Redux(1)
React:快速上手(4)——掌握Redux
引入Redux
混乱的state管理
随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态)。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

管理大量的state并不容易,当系统变得错综复杂的时候,想重现问题或者添加新功能变得举步维艰。
Redux试图让state的变化变得可以预测。

Redux的核心概念
比如我们要完成一个TODO项目,首先我们要有一个模型Model来描述应用的状态state,它可能是下面这样:
var state = {
todos:[
{text:'吃饭',completed:false},
{text:'喝水',completed:true},
{text:'睡觉',completed:false},
],
visibilityFilter:'SHOW_ALL'
}
在Redux的理论中,如果想更新应用的state,我们不再直接对它进行修改,而是需要发起一个action,它是一个普通的JavaScript对象,用来描述发生了什么
{ type: 'ADD_TODO', text: '去泳池' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETE' }
强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。最终,为了把 action 和 state 串起来,开发一些函数,这就是 reducer。
//reducer:接受一个state和action,并返回新的state的函数
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }]);
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index ?
{ text: todo.text, completed: !todo.completed } :
todo
)
default:
return state;
}
}
通过上述,我们知道使用 action 来描述“发生了什么”,和使用 reducers 来根据 action 更新 state 。
store是将所有的这些细节封装在一起的对象,它有以下职责:
- 维持应用的 state;
- 提供
getState()方法获取 state; - 提供
dispatch(action)方法更新 state; - 通过
subscribe(listener)注册监听器; - 通过
subscribe(listener)返回的函数注销监听器。
它的内部实现大概是这个样子的:
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};
dispatch({});
return { getState, dispatch, subscribe };
};
说明: Redux 应用只有一个单一的 state。当需要拆分数据处理逻辑时,你应该使用 reducer组合。。
根据已有的 reducer 来创建 store 是非常容易的,用Redux提供的createStore方法,如下:
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)
createStore() 的第二个参数是可选的, 用于设置 state 初始状态。这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。
如下这张图可以帮助我们加深理解

Reducer的划分
Reducer函数负责生成state,一个庞大的项目却只有一个state,必然会导致reducers会变得异常肿大,所以我们就不能单单写一个reduce,我们可以根据项目实际需求,分成多个reduce。
多个reduce
const todos =(state=[],action)=>{
switch(action.type){
case 'ADD_TODO':
return state.concat([{text:action.text,completed:false}])
default:
return state
}
}
const visibilityFilter = (state=[],action) =>{
switch(action.type){
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
这样一拆,Reducer 就易读易写多了。而且,这种拆分与 React 应用的结构相吻合:一个 React 根组件由很多子组件构成。这就是说,子组件与子 Reducer 完全可以对应。
Redux 提供了一个combineReducers方法,用于 Reducer 的合并。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。
//通过combineReducers来合并多个reduce
const rootReduce = combineReducers({
todos:todos,
visibilityFilter:visibilityFilter
}) store = createStore(rootReduce)
将reduce放置在同一个文件夹下
你可以把所有子 Reducer 放在一个文件里面,然后统一引入。
import { combineReducers } from 'redux'
import * as reducers from './reducers'
const reducer = combineReducers(reducers)
实例:计数器
const Counter = ({ value, onIncrement, onDecrement }) => (
<div>
<h1>{value}</h1>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
);
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
};
const store = createStore(reducer);
const render = () => {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => store.dispatch({type: 'INCREMENT'})}
onDecrement={() => store.dispatch({type: 'DECREMENT'})}
/>,
document.getElementById('root')
);
};
render();
store.subscribe(render);
React:快速上手(4)——掌握Redux(1)的更多相关文章
- React:快速上手(5)——掌握Redux(2)
React:快速上手(5)——掌握Redux(2) 本文部分内容参考阮一峰的Redux教程. React-Redux原理 React-Redux运行机制 我觉得这张图清楚地描述React-Redux的 ...
- React:快速上手(7)——使用中间件实现异步操作
React:快速上手(7)——使用中间件实现异步操作 本文参考链接:Stack Overflow redux-thunk 我们使用store.dispath进行派发时,只能传递一个普通对象进去,如下: ...
- 官方 React 快速上手脚手架 create-react-app
此文简单讲解了官方 React 快速上手脚手架的安装与介绍. 1. React 快速上手脚手架 create-react-app 为了快速地进行构建使用 React 的项目,FaceBook 官方发布 ...
- React:快速上手(6)——掌握React Router
React:快速上手(6)——掌握React Router 引入Router 安装 npm install react-router-dom 基础组件 React Router中有三种类型的组件:路由 ...
- React:快速上手(3)——列表渲染
React:快速上手(3)——列表渲染 使用map循环数组 了解一些ES6 ES6, 全称 ECMAScript 6.0 ,是 JaveScript 的下一个版本标准,2015.06 发版.ES6 主 ...
- React:快速上手(2)——组件通信
React:快速上手(2)——组件通信 向父组件传递数据 父组件可以通过设置子组件的props属性进行向子组件传值,同时也可以传递一个回调函数,来获取到子组件内部的数据. 效果演示 子组件是输入框,父 ...
- React:快速上手(1)——基础知识
React:快速上手(1)——基础知识 React(有时叫React.js或ReactJS)是一个为数据提供渲染为HTML视图的开源JavaScript库,用于构建用户界面. JSX.元素及渲染 1. ...
- React:快速上手(8)——前后端分离的跨域访问与会话保持
React:快速上手(8)——前后端分离的跨域访问与会话保持 跨域访问 跨域是指从一个域名的网页去请求另一个域名的资源.比如从http://www.baidu.com/ 页面去请求http://www ...
- react快速上手二(使用JSX语法)
前提: 下载依赖,配置 cnpm i babel-preset-react -D JSX语法的本质: 还是以 React.createElement 的形式来实现的,并没有直接把 用户写的 HTML代 ...
随机推荐
- golang mongodb查找find demo
使用gopkg.in/mgo.v2库操作,插入操作主要使用mongodb中Collection对象的Find方法,函数原型: func (c *Collection) Find(query inter ...
- JavaWeb——过滤器
过滤器简介 WEB过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息过滤. 过滤器的工作原理和生命周期 在没有Web过滤器的情况下,用户直接访问服务器上的Web资源.但是如果存 ...
- MAC Ruby版本需要升级至2.2.2以上
第一例: 默认情况下,Mac OS X 系统已经安装好 Ruby(最新的 Mavericks 随机的 Ruby 版本为 2.0.0p247),安装在 /System/Library/Framework ...
- ADO编程:error C2011: 'LockTypeEnum' : 'enum' type redefinition
C++ Code 123 // Import the ADO type library #import "C:\\Program Files\\Common Files\\syste ...
- poj 2923(状态压缩+背包)
比较巧妙的一道题目,拿到题目就想用暴力直接搜索,仔细分析了下发现复杂度达到了2^n*n! ,明显不行,于是只好往背包上想. 于是又想二分找次数判断可行的方法,但是发现复杂度10^8还是很悬... 然后 ...
- iOS UITableView划动删除的实现
标签:划动删除 iphone 滑动删除 ios UITableView 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://rainb ...
- JavaWeb项目中文乱码问题
1.从浏览器读数据乱码(post 请求方式) 前提是前端页面是UTF-8编码,因为服务器端默认采用ISO解码,所以乱码,在读取前加上: request.setCharacterEncoding(&qu ...
- [Algorithms] Longest Increasing Subsequence
The Longest Increasing Subsequence (LIS) problem requires us to find a subsequence t of a given sequ ...
- 调试SVO_edgelet
感谢白巧克力亦唯心提供的SVO_edgelet代码,作者博客:https://blog.csdn.net/heyijia0327/article/details/61682150 程序地址: http ...
- Squid 缓存代理服务器的完整配置
Squid 缓存代理服务器 Squid 的作用 1.通过缓存的方式为用户提供web访问加速 2.对用户的web访问进行过滤控制 缓存代理服务器又分为普通代理服务器,透明代理服务器,和反向代理服务器. ...