[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 ...
随机推荐
- ListToDataTable
public static DataTable ToDataTable<T>(IEnumerable<T> collection) { var ...
- C# 合并DLL, 合并DLL进入EXE 【转】
使用方法非常简单 在项目属性窗口中,选择"生成事件",在"生成后事件命令行"下的文本框中输入 ilmerge /ndebug /t:dll /log c:/1/ ...
- 【转】.Net程序员玩转Android系列之三~快速上手
原文:http://www.cnblogs.com/HouZhiHouJueBlogs/p/3962122.html 快速环境搭建和Hello World 第一步:JAVA SDK(JDK)的安装: ...
- realloc 函数的使用
realloc 函数的使用 #include <stdio.h> #include <stdlib.h> #include <iostream> using nam ...
- 玩转createjs
标题党"玩转", 真的是在玩怎么转... 参考一篇很经典的博文:createjs入门 做移动版(750x1334)的时候出来不居中啊, 不是掉在下面就是滑到右面, canvas里面 ...
- 制作qtopia-2.2.0和qt4文件系统
转自 rootfs_qtopia_qt4.img 1. 解压rootfs_qtopia_qt4-20100816.tar.gz,得到目录rootfs_qtopia_qt4,里面内容比较大,超过了64M ...
- Network Wars
zoj2676:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1676 题意:给出一个带权无向图 ,每条边e有一个权 .求将点 ...
- 【POJ 1984】Navigation Nightmare(带权并查集)
Navigation Nightmare Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40 ...
- 【HDU 4436】 str2int (广义SAM)
str2int Problem Description In this problem, you are given several strings that contain only digits ...
- Nginx配置性能优化(转)
大多数的Nginx安装指南告诉你如下基础知识——通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了.而且,在大多数情况下,一个常规安装的nginx对你的网站来说已经能 ...