Skip to content

Normalizr 中文文档(未完待续...) #4

Open
@collinxz-coder

Description

@collinxz-coder

目录

介绍

动机

很多 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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions