Open
Description
目录
介绍
动机
很多 API 接口(无论是否公开)都返回多层嵌套的 JSON 数据。对于 JavaScript 应用程序来说,使用这些嵌套数据通常很麻烦,尤其是在那些使用了 Flux 或者 Redux 的应用中。
解决方案
Normalizr 是一个小巧且强大的工具,它通过 schema 来获取 JSON,并使用 id 返回其嵌套实体。这些实体存储在字典中。
Normalizr 就是一个数据范式化工具。
例子
下面是接口返回的嵌套数据:
[
{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
},
{
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}
];
使用 Normalizr 范式化后的数据:
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
快速开始
考虑下一个典型的博客文章。获取一篇文章的 API 可能会返回如下数据:
{
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [
{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}
]
}
我们的文章中有两个嵌套的实体:users、comments。 使用 schema,我们将数据中三个实体进行范式化:
import { normalize, schema } from 'normalizr';
// 定义用户 schema
const user = new schema.Entity('users');
// 定义评论 schema
const comment = new schema.Entity('comments', {
commenter: user
});
// 定义文章的 schema
const article = new schema.Entity('articles', {
author: user,
comments: [comment]
});
const normalizedData = normalize(originalData, article);
下面是 normalizedData
的数据:
{
result: "123",
entities: {
"articles": {
"123": {
id: "123",
author: "1",
title: "My awesome blog post",
comments: [ "324" ]
}
},
"users": {
"1": { "id": "1", "name": "Paul" },
"2": { "id": "2", "name": "Nicole" }
},
"comments": {
"324": { id: "324", "commenter": "2" }
}
}
}
API
normalize(data, schema)
根据提供的 schema 来将数据范式化。
data
: (required) 需要被范式化的 JSON (或者 JS 对象) 数据schema
: (required) 必须的模式定义
用法
import { normalize, schema } from 'normalizr';
const myData = { users: [{ id: 1 }, { id: 2 }] };
const user = new schema.Entity('users');
const mySchema = { users: [user] };
const normalizedData = normalize(myData, mySchema);
输出
{
result: { users: [ 1, 2 ] },
entities: {
users: {
'1': { id: 1 },
'2': { id: 2 }
}
}
}
denormalize(input, schema, entities)
通过 schema 对 input 中指定的值进行反范式化,entities 通常是普通对象或者不可变数据(immutable)来提供。这个函数的作用是 normalize 的反操作。
特别说明:谨慎使用 denormalize,过早的将数据恢复成大型的嵌套对象,可能会对 React(和其它) 应用程序造成性能影响。
如果你的 schema 和数据具有递归应用,在会给出实体的第一个实例,后续的引用将作为提供的 id 返回。
input
: (required) 需要被反范式化的范式化数据,通常与 normalize 输出的结果中 result 键中给出的值相同。schema
: (required) 用户从 input 中获取值的 schema.entities
: (required) 一个对象,其中可能有 schema 指定的键。还可以接受不可变数据。
用法
import { denormalize, schema } from 'normalizr';
const user = new schema.Entity('users');
const mySchema = { users: [user] };
const entities = { users: { '1': { id: 1 }, '2': { id: 2 } } };
const denormalizedData = denormalize({ users: [1, 2] }, mySchema, entities);
输出
{
users: [{ id: 1 }, { id: 2 }];
}
schema
Array(definition, schemaAttribute)
创建一个 schema 来范式化数组。如果输入值是一个对象而不是数组,范式化结果将是对象值组成的数组。
可以使用简写方式:[mySchema]
- definition: (required) 一单个 schema 或者模式到属性值的映射
- schemaAttribute: (optional,如果 definition 的值不是单个 schema 时,此参数时必传) 通过指定属性来定义范式化时使用的 schema。这个参数可以接受一个字符串或者方法。这个方法有如下几个参数:
- value: 实体的输入值
- parent: 输入数组的父对象
- key: 输入数组出现在复对象上的键
实例方法
- define(definition): 使用时,传入的定义将与传递给Array构造函数的原始定义合并。这个方法在创建循环引用的时候很有用。
用法
要描述单个实体类型的简单数组:
const data = [{ id: '123', name: 'Jim' }, { id: '456', name: 'Jane' }];
const userSchema = new schema.Entity('users');
const userListSchema = new schema.Array(userSchema);
// 或者可以使用下面的简写语法
const userListSchema = [userSchema];
const normalizedData = normalize(data, userListSchema);
输出
{
entities: {
users: {
'123': { id: '123', name: 'Jim' },
'456': { id: '456', name: 'Jane' }
}
},
result: [ '123', '456' ]
}
如果你的数据是包含多个实体类型的复杂数据,则必须定义 schema 映射。
如果您的数据返回了未提供映射的对象,则原始对象将在结果中返回,并且不会创建实体
For example:
const data = [{ id: 1, type: 'admin' }, { id: 2, type: 'user' }];
const userSchema = new schema.Entity('users');
const adminSchema = new schema.Entity('admins');
const myArray = new schema.Array(
{
admins: adminSchema,
users: userSchema
},
(input, parent, key) => `${input.type}s`
);
const normalizedData = normalize(data, myArray);
输出
{
entities: {
admins: { '1': { id: 1, type: 'admin' } },
users: { '2': { id: 2, type: 'user' } }
},
result: [
{ id: 1, schema: 'admins' },
{ id: 2, schema: 'users' }
]
}
Metadata
Metadata
Assignees
Labels
No labels