You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+33-29Lines changed: 33 additions & 29 deletions
Original file line number
Diff line number
Diff line change
@@ -26,25 +26,29 @@ Somewhat obvious to say, the React ecosystem features many methods and tools tha
26
26
What can `react-async-iterators` be used for?
27
27
28
28
- easily consuming async iterables obtained from any library, web API or composed manually - in a React-friendly declarative fashion.
29
-
<!-- Dynamically plug and unplug them at any place across your app's component tree with automatic teardown. -->
29
+
<!--...Dynamically plug and unplug them at any place across your app's component tree with automatic teardown... -->
30
30
31
31
- unlocking new ways of expressing data flow in or between components efficiently, constricting redundant re-rendering.
32
-
<!-- made possible by the async iterables' unique properties (more on that later). -->
32
+
<!--...made possible by the async iterables' unique properties (more on that later)... -->
33
33
34
34
<!-- TODO: Should mention here (or anywhere else?) about the state of the `async-iterator-helpers-proposal`, as well as existing possibilities to create and compose async iterables via `iter-tools` and `IxJS`? -->
35
35
36
36
### Illustration:
37
37
38
+
[](https://stackblitz.com/edit/react-async-iterators-example-3?file=src%2FApp.tsx)
@@ -165,16 +169,16 @@ import { It, type IterationResult } from 'react-async-iterators';
165
169
166
170
## Consuming async iterables
167
171
168
-
Async iterables can be hooked into your components and consumed using [`<It>`]() and [`<ItMulti>`](), or their hook version counterparts [`useAsyncIter`]() and [`useAsyncIterMulti`]() respectively.
172
+
Async iterables can be hooked into your components and consumed using [`<It>`](#it) and [`<ItMulti>`](#itmulti), or their hook counterparts [`useAsyncIter`](#useasynciter) and [`useAsyncIterMulti`](#useasyncitermulti) respectively.
169
173
170
-
The iteration values and states are expressed via a consistent structure (more exaustive list in [this breakdown](#iteration-state-object-detailed-breakdown)).<br/>
174
+
The iteration values and states are expressed via a consistent structure (see exaustive list in [this breakdown](#iteration-state-object-detailed-breakdown)).<br/>
171
175
They may be accessed as follows:
172
176
173
177
```tsx
174
178
const myIter =getSomeIter(); // given some `myIter` async iterable
175
179
```
176
180
177
-
With [`<It>`]():
181
+
With [`<It>`](#it):
178
182
179
183
```tsx
180
184
import { It } from'react-async-iterators';
@@ -198,7 +202,7 @@ import { It } from 'react-async-iterators';
_Using the component form may be __typically preferrable__ over the hook form_ (e.g [`<It>`]() over [`useAsyncIter`]()) - Why? because using it, when changes in data occure - the re-rendered UI area within a component tree can be declaratively narrowed to the necessary minimum, saving other React elements that do not depend on its values from re-evaluation. On the the other hand - [`useAsyncIter`](), being a hook, must re-render the entirety of the host component's output for every new value.
219
+
_Using the component form may be __typically preferrable__ over the hook form_ (e.g [`<It>`](#it) over [`useAsyncIter`](#useasynciter)) - Why? because using it, when changes in data occure - the re-rendered UI area within a component tree can be declaratively narrowed to the necessary minimum, saving other React elements that do not depend on its values from re-evaluation. On the the other hand - [`useAsyncIter`](#useasynciter), being a hook, must re-render the entirety of the host component's output for every new value.
216
220
217
-
When segregating data flows and relationships across the components' render code like this, using the component forms - it makes for a more managable code, and might get rid of having to akwardly split components down to smaller parts just to render-optimize them when it otherwise wouldn't "feel right" to do so.
221
+
When segregating different flows of data the components' render code like this, using the component forms - it makes for a more managable code, and might get rid of having to akwardly split components down to smaller parts just to render-optimize them when it otherwise wouldn't "feel right" to do so.
218
222
219
223
220
224
@@ -234,7 +238,7 @@ When rendering a plain value, the iteration state properties behave alternativel
234
238
235
239
<br/>
236
240
237
-
_Showing [`<It>`]() being used with either plain or async iterable values, wrapped as a custom component:_
241
+
_Showing [`<It>`](#it) being used with either plain or async iterable values, wrapped as a custom component:_
@@ -399,17 +403,17 @@ When any consumer hook/component from the library detects the presence of a curr
399
403
400
404
This rule bridges the gap between async iterables which always yield asynchronously (as their yields are wrapped in promises) and React's component model in which render outputs are strictly synchronous. Due to this discrepency, for example, if the first value for an async iterable is known in advance and yielded as soon as possible - React could only grab the yielded value from it via a subsequent (immediate) run/render of the consumer hook/component (since the promise can resolve only _after_ such initial sync run/render). This issue is therefore solved by async iterables that expose a current value.
401
405
402
-
For example, the stateful iterable created from the [`useAsyncIterState`]() hook (_see [Component state as an async iterable](#component-state-as-an-async-iterable)_) applies this convention from its design, acting like a "topic" with an always-available current value that's able to signal out future changes, skipping pending phases, so there's no need to set initial starting states.
406
+
For example, the stateful iterable created from the [`useAsyncIterState`](#useasynciterstate) hook (_see [Component state as an async iterable](#component-state-as-an-async-iterable)_) applies this convention from its design, acting like a "topic" with an always-available current value that's able to signal out future changes, skipping pending phases, so there's no need to set initial starting states.
403
407
404
408
<!-- TODO: Any code sample that can/should go in here?... -->
405
409
406
410
407
411
408
412
## Formatting values
409
413
410
-
<!--(^^^ should add "and transforming iterables"?)-->
414
+
<!--TODO: ^^^ should add "and transforming iterables"? -->
411
415
412
-
When building your app with components accepting async iterable data as props, as you render these and have to provide such props - you may commonly see a need to _re-format_ held async iterables' value shapes before they're passed in those props, in order for them to match the expected shape. [`iterateFormatted`]() is an easy-to-use approach to many cases like this.
416
+
When building your app with components accepting async iterable data as props, as you render these and have to provide such props - you may commonly see a need to _re-format_ held async iterables' value shapes before they're passed in those props, in order for them to match the expected shape. [`iterateFormatted`](#iterateformatted) is an easy-to-use approach to many cases like this.
413
417
414
418
For instance, let's say we're trying to use some existing `<Select>` generic component, which supports being given its option list __in async iterable form__, so it could update its rendered dropdown in real-time as new sets of options are yielded. It is used like so;
> <br/>ℹ️ Every calls to [`iterateFormatted`]() returns a _formatted_ versions of `currenciesIter` with some transparent metadata used by library's consumers (like [`<It>`]()) to associate every transformed iterable with its original source iterable so existing iteration states can be maintained. It's therefore safe to recreate and pass on formatted iterables from repeated calls to [`iterateFormatted`]() across re-renders (as long the same source is used with it consistently).<br/><br/>
488
-
So unless you require some more elaborate transformation than simply formatting values - it might be more ergonomic to use [`iterateFormatted`]() vs manual compositions within [`React.useMemo`](https://react.dev/reference/react/useMemo), especially if dealing with multiple iterables to transform.<br/><br/>
491
+
> <br/>ℹ️ Each call to [`iterateFormatted`](#iterateformatted) returns a _formatted_ versions of `currenciesIter` with some transparent metadata, which the library's consumers (like [`<It>`](#it)) use to associate every transformed iterable with its original source iterable, and this way existing iteration states can be persisted properly. It's therefore safe to recreate and pass on formatted iterables from repeated calls to [`iterateFormatted`](#iterateformatted) across re-renders (as long the same source is used with it consistently).<br/><br/>
492
+
So unless you require some more elaborate transformation than simply formatting values - it might be more ergonomic to use [`iterateFormatted`](#iterateformatted) vs manual compositions within [`React.useMemo`](https://react.dev/reference/react/useMemo), especially if dealing with multiple iterables to transform.<br/><br/>
489
493
490
494
491
495
@@ -495,9 +499,9 @@ So unless you require some more elaborate transformation than simply formatting
495
499
496
500
As illustrated throughout this library and docs - when dealing with data in your app that's presented as an async iterable, an interesting pattern emerges; instead of a transition in app state traditionally sending down a cascading re-render through the entire tree of components underneath it to propagate the new state - your __async iterable__ objects can be distributed __once__ when the whole tree is first mounted, and when new data is then communicated through them it directly gets right to the edges of the UI tree that are concerned with it, re-rendering them exclusively and thus skipping all intermediaries.
497
501
498
-
The packaged [`useAsyncIterState`]() hook can lend this paradigm to your __component state__. It's like a [`React.useState`](https://react.dev/reference/react/useState) version that returns you _an async iterable of the state value instead of the state value_, paired with a setter function that causes the stateful iterable to yield the next states.
502
+
The packaged [`useAsyncIterState`](#useasynciterstate) hook can lend this paradigm to your __component state__. It's like a [`React.useState`](https://react.dev/reference/react/useState) version that returns you _an async iterable of the state value instead of the state value_, paired with a setter function that causes the stateful iterable to yield the next states.
499
503
500
-
The stateful iterable may be distributed via props down through any number of component levels the same way you would with classic React state, and used in conjunction with [`<It>`]() or [`useAsyncIter`](), etc. wherever it has to be rendered.
504
+
The stateful iterable may be distributed via props down through any number of component levels the same way you would with classic React state, and used in conjunction with [`<It>`](#it) or [`useAsyncIter`](#useasynciter), etc. wherever it has to be rendered.
501
505
502
506
In a glance, it's usage looks like this:
503
507
@@ -823,12 +827,12 @@ It's similar to [`<It>`](#it), only it works with any changeable number of async
0 commit comments