1 | # UID
|
2 |
|
3 | [![Build Status](https://travis-ci.org/thearnica/react-uid.svg?branch=master)](https://travis-ci.org/thearnica/react-uid)
|
4 | [![coverage-badge](https://img.shields.io/codecov/c/github/thearnica/react-uid.svg?style=flat-square)](https://codecov.io/github/thearnica/react-uid)
|
5 | [![NPM version](https://img.shields.io/npm/v/react-uid.svg)](https://www.npmjs.com/package/react-uid)
|
6 | [![Greenkeeper badge](https://badges.greenkeeper.io/thearnica/react-uid.svg)](https://greenkeeper.io/)
|
7 | [![bundle size](https://badgen.net/bundlephobia/minzip/react-uid)](https://bundlephobia.com/result?p=react-uid)
|
8 | [![downloads](https://badgen.net/npm/dm/react-uid)](https://www.npmtrends.com/react-uid)
|
9 |
|
10 | To generate a _stable_ UID/Key for a given `item`, consistently between client and server, **in 900 bytes**.
|
11 |
|
12 | ⚠️ SSR: **Not compatible with Strict or Concurent mode**. Consider using _native_ `useId`(React 18) hook instead.
|
13 |
|
14 | > If your clientside is using StrictMode it will never match SSR-ed Ids due to double invocation
|
15 |
|
16 | Example - https://codesandbox.io/s/kkmwr6vv47
|
17 |
|
18 | ## API
|
19 |
|
20 | React UID provides 3 different APIs
|
21 |
|
22 | - vanilla js API - `uid(item) -> key`
|
23 | - React Component, via renderProp based API - `<UID>{ id => <><label htmlFor={id}/><input id={id}/></>}</UID>`
|
24 | - React Hooks - `useUID`
|
25 |
|
26 | #### Javascript
|
27 |
|
28 | - `uid(item, [index])` - generates UID for an object(array, function and so on), result could be used as React `key`.
|
29 | `item` should be an object, but could be anything. In case it is not an "object", and might have non-unique value - you have to specify second argument - `index`
|
30 |
|
31 | ```js
|
32 | import { uid } from 'react-uid';
|
33 |
|
34 | // objects
|
35 | const data = [{ a: 1 }, { b: 2 }];
|
36 | data.map((item) => <li key={uid(item)}>{item}</li>);
|
37 |
|
38 | // unique strings
|
39 | const data = ['a', 'b'];
|
40 | data.map((item) => <li key={uid(item)}>{item}</li>);
|
41 |
|
42 | // strings
|
43 | const data = ['a', 'a'];
|
44 | data.map((item, index) => <li key={uid(item, index)}>{item}</li>);
|
45 | ```
|
46 |
|
47 | JS API might be NOT (multi-tenant)**SSR friendly**,
|
48 |
|
49 | #### React Components
|
50 |
|
51 | - (deprecated)`UID` - renderless container for generation Ids
|
52 | - `UIDConsumer` - renderless container for generation Ids
|
53 |
|
54 | ```js
|
55 | import {UID} from 'react-uid';
|
56 |
|
57 | <UID>
|
58 | {id => (
|
59 | <Fragment>
|
60 | <input id={id} />
|
61 | <label htmlFor={id} />
|
62 | </Fragment>
|
63 | )}
|
64 | </UID>
|
65 |
|
66 | // you can apply some "naming conventions" to the keys
|
67 | <UID name={ id => `unique-${id}` }>
|
68 | {id => (
|
69 | <Fragment>
|
70 | <input id={id} />
|
71 | <label htmlFor={id} />
|
72 | </Fragment>
|
73 | )}
|
74 | </UID>
|
75 |
|
76 | // UID also provide `uid` as a second argument
|
77 | <UID>
|
78 | {(_, uid) => (
|
79 | data.map( item => <li key={uid(item)}>{item}</li>)
|
80 | )}
|
81 | </UID>
|
82 |
|
83 | // in the case `item` is not an object, but number or string - provide and index
|
84 | <UID>
|
85 | {(_, uid) => (
|
86 | data.map( (item, index) => <li key={uid(item, index)}>{item}</li>)
|
87 | )}
|
88 | </UID>
|
89 | ```
|
90 |
|
91 | The difference between `uid` and `UID` versions are in "nesting" - any `UID` used inside another `UID` would contain "parent prefix" in the result, scoping `uid` to the local tree branch.
|
92 |
|
93 | UID might be NOT **SSR friendly**,
|
94 |
|
95 | #### Hooks (16.8+)
|
96 |
|
97 | - `useUID()` will generate a "stable" UID
|
98 | - `useUIDSeed()` will generate a seed generator, you can use for multiple fields
|
99 |
|
100 | ```js
|
101 | import { useUID, useUIDSeed } from 'react-uid';
|
102 |
|
103 | const Form = () => {
|
104 | const uid = useUID();
|
105 | return (
|
106 | <>
|
107 | <label htmlFor={uid}>Email: </label>
|
108 | <input id={uid} name="email" />
|
109 | </>
|
110 | )
|
111 | }
|
112 |
|
113 | const Form = () => {
|
114 | const seed = useUIDSeed();
|
115 | return (
|
116 | <>
|
117 | <label htmlFor={seed('email')}>Email: </label>
|
118 | <input id={seed('email')} name="email" />
|
119 | {data.map(item => <div key={seed(item)}>...</div>
|
120 | </>
|
121 | )
|
122 | }
|
123 | ```
|
124 |
|
125 | Hooks API **is SSR friendly**,
|
126 |
|
127 | ### Server-side friendly UID
|
128 |
|
129 | - `UIDReset`, `UIDConsumer`, `UIDFork` - SSR friendly UID. Could maintain consistency across renders.
|
130 | They are much more complex than `UID`, and provide functionality you might not need.
|
131 |
|
132 | The key difference - they are not using global "singlentone" to track used IDs,
|
133 | but read it from Context API, thus works without side effects.
|
134 |
|
135 | Next example will generate the same code, regardless how many time you will render it
|
136 |
|
137 | ```js
|
138 | import { UIDReset, UIDConsumer } from 'react-uid';
|
139 |
|
140 | <UIDReset>
|
141 | <UIDConsumer>
|
142 | {(id, uid) => (
|
143 | <Fragment>
|
144 | <input id={id} />
|
145 | <label htmlFor={id} />
|
146 | data.map( item => <li key={uid(item)}>{item}</li>)
|
147 | </Fragment>
|
148 | )}
|
149 | </UIDConsumer>
|
150 | </UIDReset>;
|
151 | ```
|
152 |
|
153 | **UID** is not 100% SSR friendly - use **UIDConsumer**.
|
154 |
|
155 | ### Code splitting
|
156 |
|
157 | Codesplitting may affect the order or existence of the components, so alter
|
158 | the `componentDidMount` order, and change the generated ID as result.
|
159 |
|
160 | In case of SPA, this is not something you should be bothered about, but for SSR
|
161 | this could be fatal.
|
162 |
|
163 | Next example will generate consistent keys regardless of component mount order.
|
164 | Each call to `UIDFork` creates a new branch of UIDs untangled from siblings.
|
165 |
|
166 | ```js
|
167 | import {UIDReset, UIDFork, UIDConsumer} from 'react-uid';
|
168 |
|
169 | <UIDReset>
|
170 | <UIDFork>
|
171 | <AsyncLoadedCompoent>
|
172 | <UIDConsumer>
|
173 | { uid => <span>{uid} is unique </span>}
|
174 | </UIDConsumer>
|
175 | </UIDFork>
|
176 | <UIDFork>
|
177 | <AsyncLoadedCompoent>
|
178 | <UIDConsumer>
|
179 | { uid => <span>{uid} is unique </span>}
|
180 | </UIDConsumer>
|
181 | </UIDFork>
|
182 | </UIDReset>
|
183 | ```
|
184 |
|
185 | The hooks API only needs the `<UIDFork>` wrapper.
|
186 |
|
187 | ### So hard?
|
188 |
|
189 | "Basic API" is not using Context API to keep realization simple, and React tree more flat.
|
190 |
|
191 | # Types
|
192 |
|
193 | Written in TypeScript
|
194 |
|
195 | # Licence
|
196 |
|
197 | MIT
|