目前正致力于react + redux项目.
我还使用normalizr来处理数据结构并重新选择以收集应用程序组件的正确数据.
一切似乎都运作良好.
我发现自己处于类似叶子的组件需要来自商店的数据的情况,因此我需要connect()组件来实现它.
作为一个简化示例,假设该应用程序是一个图书编辑系统,有多个用户收集反馈.
Book
Chapters
Chapter
Comments
Comments
Comments
Run Code Online (Sandbox Code Playgroud)
在应用程序的不同级别,用户可以贡献内容和/或提供评论.
考虑我正在渲染章节,它有内容(和作者)和评论(每个都有自己的内容和作者).
目前我会connect()和reselect章节内容基于ID.
因为数据库是用normalizr规范化的,所以我实际上只获得章节的基本内容字段和作者的用户ID.
为了呈现注释,我将使用一个可以重新选择链接到章节的注释的连接组件,然后单独呈现每个注释组件.
同样,因为数据库是用normalizr规范化的,所以我真的只得到评论作者的基本内容和用户ID.
现在,为了呈现像作者徽章一样简单的东西,我需要使用另一个连接的组件从我拥有的用户ID中获取用户详细信息(在呈现章节作者和每个评论作者时).
该组件将是这样简单的东西:
@connect(
createSelector(
(state) => state.entities.get('users'),
(state,props) => props.id,
(users,id) => ( { user:users.get(id)})
)
)
class User extends Component {
render() {
const { user } = this.props
if (!user)
return null
return <div className='user'>
<Avatar name={`${user.first_name} ${user.last_name}`} size={24} round={true} />
</div>
}
}
User.propTypes = {
id : …Run Code Online (Sandbox Code Playgroud) 我需要规范化这些数据,以便我有一个列表数组和另一个待办事项.
const data = [
{
_id: '1',
title: 'List1',
todos: [
{
_id: "11",
text: "Test1"
}
]
},
{
_id: '2',
title: 'List2',
todos: [
{
_id: "22",
text: "Test2"
}
]
}
];
Run Code Online (Sandbox Code Playgroud)
这是我得到的:
const todo = new schema.Entity('todos',{},{ idAttribute: '_id'});
const list = new schema.Entity('lists',{todos:todo},{idAttribute: '_id'});
const normalizedData = normalize(data, list);
console.log(normalizedData);
Run Code Online (Sandbox Code Playgroud)
我一直在尝试他们的例子,但它们似乎都不适用于这些数据.
任何帮助,将不胜感激.
我刚开始在Redux中使用normalizr,但我陷入了一个简单的问题,但我做错了。所以我想规范化这样的数组:
{
articles: [
{id: 1, someValue: 'test'},
{id: 2, someValue: 'test2'}
]
}
Run Code Online (Sandbox Code Playgroud)
变成这样的结构:
{
result: {
articles: [1,2]
},
entities: {
articles: {
1: {someValue: 'test'},
2: {someValue: 'test2'}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试这样做:
const article = new Schema('articles');
responce = normalize(responce, {
articles: arrayOf(article)
});
Run Code Online (Sandbox Code Playgroud)
但这给了我一个看起来像这样的结构:
{
articles: {
entities: {},
result: {
0: {someValue: 'test'},
1: {someValue: 'test2'}
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在没有文章ID的数组。我假设我在这里缺少什么:
article.define({
...
});
Run Code Online (Sandbox Code Playgroud)
但是在这种简单的情况下无法确定需要去哪里
我有一个非常标准的嵌套JSON响应. 项目有很多仪表板.仪表板有很多图表.
定义和使用我的模式的正确方法是什么?
下面是我的Schemas.js的代码,我的API响应以及Normalizr将我的API响应转换为的内容.
Schemas.js:
import { Schema, arrayOf, normalize } from 'normalizr';
// Create a schema for each model.
const project = new Schema('projects');
const dashboard = new Schema('dashboard');
const chart = new Schema('chart');
// Projects have many dashboards.
project.define({
dashboards: arrayOf(dashboard)
});
// Dashboards have many charts.
dashboard.define({
charts: arrayOf(chart)
});
export const Schemas = { project, dashboard, chart };
Run Code Online (Sandbox Code Playgroud)
我的API响应:
{
projects: [{
id: 1,
name: "Project 1",
dashboards: [{ …Run Code Online (Sandbox Code Playgroud) 我正在从我的API中获取数据,并在将其转储到redux之前将其通过normalizr传递。当我从API获取人员数据时,reducer应该将其附加到人员存储中。现在,我的reducer正在覆盖存储中的所有现有数据。
减速器:
export default function reducer(state={
people: {
entities : {
people: {
0 : {
name : ''
}
}
},
result : [0,]
}
}, action) {
switch (action.type) {
case "GET_PEOPLE": {
const newpPeople = {...state.people, ...action.payload };
console.log(state.people)
console.log(action.payload)
console.log(newpPeople)
return {...state, people : newpPeople};
}
default :
return state
}
}
Run Code Online (Sandbox Code Playgroud)
该第一个控制台日志是reducer一次使用后的状态。它具有最初已保存到商店的一组人员:
{
entities: {
people : {
1 : { id: 1, name: "jim" },
2 : { id: 2, name: "billy" }
} …Run Code Online (Sandbox Code Playgroud) 我有一个包含很多嵌套实体的API响应。我使用normalizr来保持redux状态尽可能平坦。
例如。api响应如下所示:
{
"id": 1,
"docs": [
{
"id": 1,
"name": "IMG_0289.JPG"
},
{
"id": 2,
"name": "IMG_0223.JPG"
}
],
"tags": [
{
"id": "1",
"name": "tag1"
},
{
"id": "2",
"name": "tag2"
}
]
}
Run Code Online (Sandbox Code Playgroud)
normalizr使用以下给出的模式对该响应进行规范化:
const OpeningSchema = new schema.Entity('openings', {
tags: [new schema.Entity('tags')],
docs: [new schema.Entity('docs')]
});
Run Code Online (Sandbox Code Playgroud)
下面是它的外观:
{
result: "1",
entities: {
"openings": {
"1": {
"id": 1,
"docs": [1,2],
"tags": [1,2]
}
},
"docs": {
"1": {
id: "1",
"name": "IMG_0289.JPG"
}, …Run Code Online (Sandbox Code Playgroud) 我过去曾使用过immer ,并且非常喜欢它。它使得使用 redux 变得轻而易举。我最近发现了normlizr,它看起来也很棒。
两者有什么区别?immer 是否提供与 Normalizr 相同的标准化解决方案?对于生产应用程序来说,这两者中哪个是更好的选择?或者它们应该一起使用吗?
谨防!这个问题可能令人困惑并且无关紧要,因为我对错误原因的假设是错误的,问题出在减速器上,而不是我代表数据的方式。
因此,问题的正确答案是jpdelatorre的答案,而 Joao的答案是关于错误本身的。
假设我有来自服务器的JSON响应,它是一组嵌套对象。如何弄平它以使商店处理尽可能容易?我试图使用这样的normalizr工具:
const imageSchema = new Schema('image', { idAttribute: 'id' });
const tooltipSchema = new Schema('tooltips', { idAttribute: 'id' });
imageSchema.define({
tooltips: arrayOf(tooltipSchema),
});
const initData = data.map(item => normalize(item, imageSchema));
Run Code Online (Sandbox Code Playgroud)
但是我相信我做错了,因为它没有太大帮助。存储仍然太复杂,因此我需要在reducer中使用一些递归的东西来更新状态。
此外,深层嵌套的状态也使得使用react-redux变得connect()非常困难,因为它仅进行了比较浅的比较。
响应的形状如下:
[
{
"id": 1,
"title": "Partridge",
"tooltips": [
{
"id": 10,
"x": 0.56,
"y": 0.59,
"content": "Jacky"
},
{
"id": 11,
"x": 0.08,
"y": 0.8,
"content": "Sarah"
}
]
},
{
"id": 2,
"title": "The Great Seal …Run Code Online (Sandbox Code Playgroud) 我的 api 的当前响应如下:
[
{
"device_id": "1234",
"network_status": "Offline",
"status": "Yes",
"frequency": 50,
},
{
"device_id": "12345",
"network_status": "online",
"status": "no",
"frequency": 123,
},
{
"device_id": "12346",
"network_status": "online",
"status": "no",
"frequency": 423,
},
]
Run Code Online (Sandbox Code Playgroud)
使用最新文档: https://github.com/paularmstrong/normalizr/blob/master/docs/api.md#arraydefinition-schemaattribute
我知道这些文档已经更新,因此查看堆栈上的其他问题我无法找到类似的示例。“responseData”包含来自 api 的响应,它是一个对象数组。[{},{},...]
我的代码是
import { schema } from 'normalizr';
const deviceid = new schema.Entity('device_id');
const arrayOfDevices = new schema.Array({
device_id : deviceid,
})
normalize(responseData, arrayOfDevices)
Run Code Online (Sandbox Code Playgroud)
我想得到以下输出。将 device_id 作为每个对象的键的实体对象。
{
entities: {
device_id: {
'1234' : {
.....
},
'12345' : {
..... …Run Code Online (Sandbox Code Playgroud) 我使用Normalizr从不同的API端点获得相同的响应形状.
const post = new Schema('posts');
const posts = arrayOf('post');
const listResponse = [
{id: 1, text: 'post one'},
{id: 2, text: 'post two'},
];
normalize(listResponse, posts);
/*
{
entities: {
posts: {
1: {id: 1, text: 'post one'},
2: {id: 2, text: 'post two'}
}
},
result: [1, 2]
}
*/
const singleResponse = {id: 1, text: 'post one'};
normalize(singleResponse, post);
/*
{
entities: {
posts: {
1: {id: 1, text: 'post one'}
}
},
result: 1
}
*/ …Run Code Online (Sandbox Code Playgroud)