[Redux] Normalizing the State Shape
We will learn how to normalize the state shape to ensure data consistency that is important in real-world applications.
We currently represent the todos in the state free as an array of todo object. However, in the real app, we probably have more than a single array and then todos with the same IDs in different arrays might get out of sync.
const byIds = (state = {}, action) => {
switch (action.type) {
case 'ADD_TODO':
case 'TOGGLE_TODO':
return {
...state,
[action.id]: todo(state[action.id], action),
};
default:
return state;
}
};
For using object spread, we need to include plugins:
// .baberc
{
"presets": ["es2015", "react"],
"plugins": ["transform-object-rest-spread"]
}
Anytime the ByID reducer receives an action, it's going to return the copy of its mapping between the IDs and the actual todos with updated todo for the current action. I will let another reducer that keeps track of all the added IDs.
const allIds = (state = [], action) => {
switch(action.type){
case 'ADD_TODO':
return [...state, action.id];
default:
return state;
}
};
the only action I care about is a todo because if a new todo is added, I want to return a new array of IDs with that ID as the last item. For any other actions, I just need to return the current state.
Finally, I still need to export the single reducer from the todos file, so I'm going to use combined reducers again to combine the ByID and the AllIDs reducers.
const todos = combineReducers({
allIds,
byIds
});
export default todos;
Now that we have changed the state shape in reducers, we also need to update the selectors that rely on it. The state object then get visible todos is now going to contain ByID and AllIDs fields, because it corresponds to the state of the combined reducer.
const getAllTodos = (state) => {
return state.allIds.map( (id) => {
return state.byIds[id];
})
};
export const getVisibleTodos = (state, filter) => {
const allTodos = getAllTodos(state);
console.log(allTodos);
switch (filter) {
case 'all':
return allTodos;
case 'completed':
return allTodos.filter(t => t.completed);
case 'active':
return allTodos.filter(t => !t.completed);
default:
throw new Error(`Unknown filter: ${filter}.`);
}
};

My todos file has grown quite a bit so it's a good time to extract the todo reducer that manages just when you go todo into a separate file of its own. I created a file called todo in the same folder and I will paste my implementation right there so that I can import it from the todos file.
// reducers/todo.js
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false,
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state,
completed: !state.completed,
};
default:
return state;
}
};
------------------
//todos.js
import { combineReducers } from 'redux';
import todo from './todo';
const byIds = (state = {}, action) => {
switch (action.type) {
case 'ADD_TODO':
case 'TOGGLE_TODO':
return {
...state,
[action.id]: todo(state[action.id], action),
};
default:
return state;
}
};
const allIds = (state = [], action) => {
switch(action.type){
case 'ADD_TODO':
return [...state, action.id];
default:
return state;
}
};
const todos = combineReducers({
allIds,
byIds
});
export default todos;
const getAllTodos = (state) => {
return state.allIds.map( (id) => {
return state.byIds[id];
})
};
export const getVisibleTodos = (state, filter) => {
const allTodos = getAllTodos(state);
console.log(allTodos);
switch (filter) {
case 'all':
return allTodos;
case 'completed':
return allTodos.filter(t => t.completed);
case 'active':
return allTodos.filter(t => !t.completed);
default:
throw new Error(`Unknown filter: ${filter}.`);
}
};
//todo.js
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false,
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state,
completed: !state.completed,
};
default:
return state;
}
}; export default todo;
[Redux] Normalizing the State Shape的更多相关文章
- 关于props和state以及redux中的state
React的数据模型分为共有数据和私有数据,共有数据可以在组件间进行传递,私有数据为当前组件私有.共有数据在React中使用props对象来调用,它包含标签所有的属性名称和属性值,props对象有三个 ...
- [Redux] Persisting the State to the Local Storage
We will learn how to use store.subscribe() to efficiently persist some of the app’s state to localSt ...
- [Functional Programming ADT] Create a Redux Store for Use with a State ADT Based Reducer
With a well defined demarcation point between Redux and our State ADT based model, hooking up to a R ...
- 前端(十一):props、state及redux关系梳理
所谓状态机,是一种抽象的数据模型,是“事物发展的趋势”,其原理是事件驱动.广泛地讲,世界万物都是状态机. 一.状态机是一种抽象的数据模型 在react中,props和state都可以用来传递数据.这里 ...
- Redux的State不应该全部放在Store里
使用了redux管理应用的状态,应用的状态不应该全部放在Store里面. 前端状态主要有一下两种: 1. Domain data 2. UI State 1. Domain data 来自于服务端对领 ...
- [Redux] Colocating Selectors with Reducers
We will learn how to encapsulate the knowledge about the state shape in the reducer files, so that t ...
- 详解 Node + Redux + MongoDB 实现 Todolist
前言 为什么要使用 Redux? 组件化的开发思想解放了繁琐低效的 DOM 操作,以 React 来说,一切皆为状态,通过状态可以控制视图的变化,然后随着应用项目的规模的不断扩大和应用功能的不断丰富, ...
- redux的源码解析
一. redux出现的动机 1. Javascript 需要管理比任何时候都要多的state2. state 在什么时候,由于什么原因,如何变化已然不受控制.3. 来自前端开发领域的新需求4. 我们总 ...
- [Redux] Important things in Redux
Root Smart component can be overloaded, divide 'smart' component wisely & using Provider. Proble ...
随机推荐
- bzoj4038: 医疗援助
Description 一只带着先进设备和药物的医疗团队来到了埃博拉病毒疫区的某个非洲国家.这个国家有n个村庄,均坐落在该国唯一的一条公路旁,n个村庄依次标号为1,2,…n.第i个村庄有a_i个埃博拉 ...
- 向SDE图层中添加大量数据时,出现ORA-00604以及ORA-01000的解决办法
转自原文 向SDE图层中添加大量数据时,出现ORA-00604以及ORA-01000的解决办法 写了一个小程序,从一个列表中读取坐标串,每个坐标串生成一个IPolygon,然后将这些Polygon添加 ...
- HTML -- 元素和属性
HTML -- 元素 HTML元素是从开始标签到结束标签之间的代码,如: <!-- 加粗标签 --> <b>一些元素</b> <!-- 换行 --> & ...
- 一篇文章让你彻底搞清楚Python中self的含义
刚开始学习Python的类写法的时候觉得很是麻烦,为什么定义时需要而调用时又不需要,为什么不能内部简化从而减少我们敲击键盘的次数? 你看完这篇文章后就会明白所有的疑问. self代表类的实例,而非类. ...
- C/S和B/S两种软件体系结构
目前两种流行的软件体系结构就是C/S和B/S体系结构,下面对两种体系结构进行一下总结: 1.C/S(客户端/服务器模式): 客户端和服务器都是独立的计算机,客户端是面向最终用户的应用程序或一些接口设备 ...
- int 占一个机器字长
int与short int是不一样的. C++标准规定,int占一个机器字长.在32位系统中int占32位,也就是4个字节, 而在老式的16位系统中,int占16位,即2个字节. 而C++标准中只限制 ...
- JavaScript自学代码--(四)
//JavaScript Window - 浏览器对象模型 window.document.getElementById("header"); //等价于 document.get ...
- Linq查询出结果集中重复数据
private List<FMDS_FarmPlotNewInfo> GetSame(List<FMDS_FarmPlotNewInfo> lst) { List<FMD ...
- RocketMQ在windows上安装和开发使用
1.概述 RocketMQ是alibaba公司开源的一个纯java的开源消息中间件. 2.开发测试环境搭建 到github上面rocketMQ,我选择的是alibaba-rocketmq-3.2.6. ...
- 《鸟哥的Linux私房菜》读书笔记一
1.CPU为一个具有特定功能的芯片,里面含有微指令集,一个CPU又可以分为两个主要的单元:算术逻辑单元和控制单元.CPU读取的数据都是从内存读取来的,内存内的数据是从输入单元传输来的.CPU处理完也要 ...