From 67f4e0b45068da32d20e250267cb1cd2cea51226 Mon Sep 17 00:00:00 2001 From: Nathaniel Tucker Date: Mon, 18 Dec 2023 13:21:52 +0000 Subject: [PATCH] docs: Update normalizr readme --- .changeset/odd-cars-cheer.md | 5 ++ docs/rest/api/schema.md | 3 - packages/normalizr/README.md | 132 ++++++++++++++++++++++++++++----- packages/normalizr/docs/api.md | 12 ++- 4 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 .changeset/odd-cars-cheer.md diff --git a/.changeset/odd-cars-cheer.md b/.changeset/odd-cars-cheer.md new file mode 100644 index 000000000000..2fd8c9434f6c --- /dev/null +++ b/.changeset/odd-cars-cheer.md @@ -0,0 +1,5 @@ +--- +"@data-client/normalizr": patch +--- + +Update README diff --git a/docs/rest/api/schema.md b/docs/rest/api/schema.md index 9631b22b12ad..b3b56fbdeda4 100644 --- a/docs/rest/api/schema.md +++ b/docs/rest/api/schema.md @@ -92,14 +92,12 @@ class Article extends Entity { import { schema, Entity } from '@data-client/endpoint'; import { Temporal } from '@js-temporal/polyfill'; -// Define a users schema class User extends Entity { pk() { return this.id; } } -// Define your comments schema class Comment extends Entity { pk() { return this.id; @@ -111,7 +109,6 @@ class Comment extends Entity { }; } -// Define your article class Article extends Entity { pk() { return this.id; diff --git a/packages/normalizr/README.md b/packages/normalizr/README.md index 6416414c659a..167d13c6203f 100644 --- a/packages/normalizr/README.md +++ b/packages/normalizr/README.md @@ -1,4 +1,4 @@ -# normalizr +# Normalizr Client [![CircleCI](https://circleci.com/gh/reactive/data-client/tree/master.svg?style=shield)](https://circleci.com/gh/data-clientdata-clients) [![Coverage Status](https://img.shields.io/codecov/c/gh/reactive/data-client/master.svg?style=flat-square)](https://app.codecov.io/gh/data-clientdata-clients?branch=master) @@ -35,9 +35,17 @@ Normalizr is a small, but powerful utility for taking JSON with a schema definit ## Examples -- [Normalizing GitHub Issues](/examples/normalizr-github) -- [Relational Data](/examples/normalizr-relationships) -- [Interactive Redux](/examples/normalizr-redux) +- [Normalizing GitHub Issues](../../examples/normalizr-github) +- [Relational Data](../../examples/normalizr-relationships) +- [Interactive Redux](../../examples/normalizr-redux) +- [Benchmarks](../../examples/benchmark) + - [Charts](https://reactive.github.io/data-client/dev/bench/) + +## React Demos + +- [Todo Demo](https://stackblitz.com/github/reactive/data-client/tree/master/examples/todo-app?file=src%2Fpages%2FHome%2FTodoList.tsx) +- [Github Demo](https://stackblitz.com/github/reactive/data-client/tree/master/examples/github-app?file=src%2Fpages%2FIssueList.tsx) +- [NextJS SSR Demo](https://stackblitz.com/github/reactive/data-client/tree/master/examples/nextjs?file=pages%2FAssetPrice.tsx) ## Quick Start @@ -54,19 +62,29 @@ Consider a typical blog post. The API response for a single post might look some "comments": [ { "id": "324", + "createdAt": "2013-05-29T00:00:00-04:00", "commenter": { "id": "2", "name": "Nicole" } + }, + { + "id": "544", + "createdAt": "2013-05-30T00:00:00-04:00", + "commenter": { + "id": "1", + "name": "Paul" + } } ] } ``` -We have two nested entity types within our `article`: `users` and `comments`. Using various `schema`, we can normalize all three entity types down: +We have two [nested](https://dataclient.io/rest/guides/relational-data) [entity](https://dataclient.io/rest/api/Entity) types within our `article`: `users` and `comments`. Using various [schema](https://dataclient.io/rest/api/Entity#schema), we can normalize all three entity types down: ```js -import { normalize, schema, Entity } from '@data-client/normalizr'; +import { schema, Entity } from '@data-client/endpoint'; +import { Temporal } from '@js-temporal/polyfill'; // Define a users schema class User extends Entity { @@ -83,6 +101,7 @@ class Comment extends Entity { static schema = { commenter: User, + createdAt: Temporal.Instant.from, }; } @@ -97,41 +116,116 @@ class Article extends Entity { comments: [Comment], }; } +``` + +### Normalize -const normalizedData = normalize(originalData, Article); +```js +import { normalize } from '@data-client/normalizr'; + +const args = [{ id: '123' }]; +const normalizedData = normalize(originalData, Article, args); ``` -Now, `normalizedData` will be: +Now, `normalizedData` will create a single serializable source of truth for all entities: ```js { result: "123", entities: { - "Article": { + articles: { "123": { id: "123", author: "1", title: "My awesome blog post", - comments: [ "324" ] + comments: [ "324", "544" ] } }, - "User": { + users: { "1": { "id": "1", "name": "Paul" }, "2": { "id": "2", "name": "Nicole" } }, - "Comment": { - "324": { id: "324", "commenter": "2" } + comments: { + "324": { + id: "324", + createdAt: "2013-05-29T00:00:00-04:00", + commenter: "2" + }, + "544": { + id: "544", + createdAt: "2013-05-30T00:00:00-04:00", + commenter: "1" + } } - } + }, +} +``` + +`normalizedData` can be placed in any flux store as the single source of truth for this data. + +### Denormalize + +Accessing the store can then be done using flux `selectors` by `denormalizing`: + +```js +import { denormalize } from '@data-client/normalizr'; + +const denormalizedData = denormalize( + normalizedData.result, + Article, + normalizedData.entities, + args, +); +``` + +Now, `denormalizedData` will instantiate the classes, ensuring all instances of the same member (like `Paul`) are referentially equal: + +```js +Article { + id: '123', + title: 'My awesome blog post', + author: User { id: '1', name: 'Paul' }, + comments: [ + Comment { + id: '324', + createdAt: Instant [Temporal.Instant] {}, + commenter: [User { id: '2', name: 'Nicole' }] + }, + Comment { + id: '544', + createdAt: Instant [Temporal.Instant] {}, + commenter: [User { id: '1', name: 'Paul' }] + } + ] } ``` -## Dependencies +### Memoizing results + +`denormalizeCached` can also be used to maintain referential equality between calls as well +as potentially improved performance by 2000%. -None. +```js +import { WeakEntityMap, denormalizeCached } from '@data-client/normalizr'; + +// maintain these cache variables unless you want to reset the cache +const entityCache = {}; +const resultCache = new WeakEntityMap(); + +const { data: denormalizedData, paths } = denormalizeCached( + normalizedData.result, + Article, + normalizedData.entities, + entityCache, + resultCache, + args, +); +``` + +`paths` is an Array of paths of all entities included in the result. ## Credits -Normalizr was originally created by [Dan Abramov](http://github.com/gaearon) and inspired by a conversation with [Jing Chen](https://twitter.com/jingc). Since v3, it was completely rewritten and maintained by [Paul Armstrong](https://twitter.com/paularmstrong). -Since v4, it was largely rewritten and maintained by [Nathaniel Tucker](https://twitter.com/npinp). -It has also received much help, enthusiasm, and contributions from [community members](https://github.com/ntucker/normalizr/graphs/contributors). +Normalizr Client is based on [Normalizr](https://github.com/paularmstrong/normalizr) - originally created by [Dan Abramov](http://github.com/gaearon) and inspired by a conversation with [Jing Chen](https://twitter.com/jingc). Since v3, it was completely rewritten and maintained by [Paul Armstrong](https://twitter.com/paularmstrong). + +Normalizr Client was rewritten and maintained by Normalizr contributor [Nathaniel Tucker](https://twitter.com/npinp). It has also received much help, enthusiasm, and contributions from [community members](https://github.com/ntucker/normalizr/graphs/contributors). diff --git a/packages/normalizr/docs/api.md b/packages/normalizr/docs/api.md index bd0ce0be4dc3..a14e7185edb1 100644 --- a/packages/normalizr/docs/api.md +++ b/packages/normalizr/docs/api.md @@ -19,7 +19,8 @@ Normalizes input data per the schema definition provided. ### Usage ```js -import { normalize, schema } from '@data-client/normalizr'; +import { schema } from '@data-client/endpoint'; +import { normalize } from '@data-client/normalizr'; const myData = { users: [{ id: 1 }, { id: 2 }] }; const user = new schema.Entity('users'); @@ -56,7 +57,8 @@ If your schema and data have recursive references, only the first instance of an ### Usage ```js -import { denormalize, schema } from '@data-client/normalizr'; +import { schema } from '@data-client/endpoint'; +import { denormalize } from '@data-client/normalizr'; const user = new schema.Entity('users'); const mySchema = { users: [user] }; @@ -95,6 +97,8 @@ _Note: The same behavior can be defined with shorthand syntax: `[ mySchema ]`_ To describe a simple array of a singular entity type: ```js +import { schema } from '@data-client/endpoint'; + const data = [{ id: '123', name: 'Jim' }, { id: '456', name: 'Jane' }]; const userSchema = new schema.Entity('users'); @@ -126,6 +130,8 @@ _Note: If your data returns an object that you did not provide a mapping for, th For example: ```js +import { schema } from '@data-client/endpoint'; + const data = [{ id: 1, type: 'admin' }, { id: 2, type: 'user' }]; const userSchema = new schema.Entity('users'); @@ -379,6 +385,8 @@ _Note: If your data returns an object that you did not provide a mapping for, th For example: ```js +import { schema } from '@data-client/endpoint'; + const data = { '1': { id: 1, type: 'admin' }, '2': { id: 2, type: 'user' }