[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 ...
随机推荐
- leetcode 组合题
1.Subsets 代码1: class Solution { public: vector<vector<int> > subsets(vector<int> & ...
- Xcode7.01相对于底版本的变动小结
1.在Xcode7中系统不再自动支持http请求,需要配置plist才能使用http: 2.appdelegate中的self.window不再支持直接往window上加view,必须先给window ...
- 【转载】C# Tutorial - Simple Threaded TCP Server
http://tech.pro/tutorial/704/csharp-tutorial-simple-threaded-tcp-server In this tutorial I'm going t ...
- HTTP状态码——对照表
ASCII码介绍: HTTP状态码(HTTP Status Code)用来表示web服务器响应客户端的HTTP状态.主要有一下5种状态类型.1xx 消息2xx 成功3xx 重定向4x ...
- C# XML与对象互相转换
using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; u ...
- 使用libsvm对MNIST数据集进行实验
使用libsvm对MNIST数据集进行实验 在学SVM中的实验环节,老师介绍了libsvm的使用.当时看完之后感觉简单的说不出话来. 1. libsvm介绍 虽然原理要求很高的数学知识等,但是libs ...
- Entity Framework快速入门--IQueryable与IEnumberable的区别(转载)
IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...
- C++ Prime:指针和const
与引用一样,也可以令指针指向常量或非常量,类似于常量引用,指向常量的指针不能用于改变其所指对象的值.要想存放常量对象的地址,只能使用指向常量的指针: const double pi = 3.14; / ...
- bzoj1406
这道题很有意思 我们解过线性同余方程,也解过同余方程 这个则是求x^2≡1 (mod p) 可以将问题转化为(x-1)(x+1)≡0 (mod p) 然后我们穷举一下p的约数i, 看i|x-1,p/i ...
- C#获取文件的当前路径
C#获取文件的当前路径 1. System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName -获取模块的完整路径. 2.Syst ...