[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 ...
随机推荐
- (转) 各种好用的插件 Xcode
时间就是金钱.编码效率的提升意味着更多的收入.可是当我们的开发技巧已经到达一定高度时,如何让开发效率更上一层楼呢?答案就是使用开发工具!在这篇文章中,我会向你介绍一些帮助我提升编码速度和工作效率的工具 ...
- jquery仿ios日期时间插件
Demo下载: 手机时间控件.zip 使用之前,请在页面中加入以下js和css: jquery-1.9.1.js mobiscroll.core-2.5.2.js mobiscroll.core-2. ...
- [Android应用]《花界》V1.0 正式版隆重发布!
http://www.cnblogs.com/qianxudetianxia/archive/2012/04/05/2433669.html 1. 软件说明(1). 花界是一款看花软件:“看花,议花, ...
- WEB SSH之Shellinabox
用起来方便的,参考URL: http://lzw.me/a/shellinabox.html 生成 pem 证书,可以 https 方式启动.pem 证书的格式为公钥加私钥,并以 x509 的格式进行 ...
- 【POJ 3162】 Walking Race (树形DP-求树上最长路径问题,+单调队列)
Walking Race Description flymouse's sister wc is very capable at sports and her favorite event is ...
- 【poj3734】矩阵乘法求解
[题意] 给N个方块排成一列.现在要用红.蓝.绿.黄四种颜色的油漆给这些方块染色.求染成红色方块和染成绿色方块的个数同时为偶数的染色方案的个数,输出对10007取余后的答案.(1<=n<= ...
- Android用户界面 UI组件--AdapterView及其子类(二) AdapterViewAnimator及其子类
AdapterViewAnimator:当在视图间切换时会显示动画. android:animateFirstView 定义ViewAnimation首次显示时是否对当前视图应用动画. android ...
- Delphi实现无标题有边框的窗体
1.在delphi中新建窗体程序,然后设置窗口的 BorderStyle属性为bsNone 2.在窗体的public区写下这一句: Procedure CreateParams(var Params ...
- delphi非IE内核浏览器控件TEmbeddedChrome下载|TEmbeddedChrome代码
下载地址: 点击下载 代码示例: 在TForm的oncreate方法中写入一些代码 procedure TForm1.FormCreate(Sender: TObject); begin Chromi ...
- android Button隐藏
两种方式: xml方式 和 java代码方式: 可见(visible) XML文件:android:visibility="visible" Java代码:view.setVisi ...