Skip to content

Commit 8a6fc81

Browse files
authored
docs(readme): more edits (#66)
1 parent 3a256e8 commit 8a6fc81

File tree

1 file changed

+33
-29
lines changed

1 file changed

+33
-29
lines changed

README.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,25 +26,29 @@ Somewhat obvious to say, the React ecosystem features many methods and tools tha
2626
What can `react-async-iterators` be used for?
2727

2828
- 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... -->
3030

3131
- 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)... -->
3333

3434
<!-- 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`? -->
3535

3636
### Illustration:
3737

38+
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/edit/react-async-iterators-example-3?file=src%2FApp.tsx)
39+
3840
```tsx
3941
import { It } from 'react-async-iterators';
4042

41-
const randoms = (async function* () {
42-
while (true) {
43-
await new Promise(r => setTimeout(r, 1000));
44-
const x = Math.random();
45-
yield Math.round(x * 10);
46-
}
47-
})();
43+
const randoms = {
44+
async *[Symbol.asyncIterator]() {
45+
while (true) {
46+
await new Promise((r) => setTimeout(r, 500));
47+
const x = Math.random();
48+
yield Math.round(x * 10);
49+
}
50+
},
51+
};
4852

4953
// and then:
5054

@@ -57,13 +61,13 @@ const randoms = (async function* () {
5761
<It value={randoms}>
5862
{next => (
5963
next.pendingFirst
60-
? 'Loading first...'
61-
: <p>{next.value.toExponential()}</p>
64+
? 'Loading first...'
65+
: <p>{next.value?.toExponential()}</p>
6266
)}
6367
</It>
6468

6569
// renders:
66-
// 'Loading first...'
70+
// 'Loading first...'
6771
// <p>2e+0</p>...
6872
// <p>1e+0</p>...
6973
// <p>3e+0</p>...
@@ -165,16 +169,16 @@ import { It, type IterationResult } from 'react-async-iterators';
165169

166170
## Consuming async iterables
167171

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.
169173

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/>
171175
They may be accessed as follows:
172176

173177
```tsx
174178
const myIter = getSomeIter(); // given some `myIter` async iterable
175179
```
176180

177-
With [`<It>`]():
181+
With [`<It>`](#it):
178182

179183
```tsx
180184
import { It } from 'react-async-iterators';
@@ -198,7 +202,7 @@ import { It } from 'react-async-iterators';
198202
</It>
199203
```
200204

201-
With [`useAsyncIter`]():
205+
With [`useAsyncIter`](#useasynciter):
202206

203207
```tsx
204208
import { useAsyncIter } from 'react-async-iterators';
@@ -212,9 +216,9 @@ next.done;
212216
next.error;
213217
```
214218

215-
_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.
216220

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.
218222

219223

220224

@@ -234,7 +238,7 @@ When rendering a plain value, the iteration state properties behave alternativel
234238
235239
<br/>
236240

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:_
238242

239243
```tsx
240244
import { It, type MaybeAsyncIterable } from 'react-async-iterators';
@@ -399,17 +403,17 @@ When any consumer hook/component from the library detects the presence of a curr
399403

400404
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.
401405

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.
403407

404408
<!-- TODO: Any code sample that can/should go in here?... -->
405409

406410

407411

408412
## Formatting values
409413

410-
<!-- (^^^ should add "and transforming iterables"?) -->
414+
<!-- TODO: ^^^ should add "and transforming iterables"? -->
411415

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.
413417

414418
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;
415419

@@ -438,7 +442,7 @@ const currenciesIter = getAvailableCurrenciesIter();
438442

439443
As apparent, the value types between these two are not compatible (properties are not matching).
440444

441-
By using [`iterateFormatted`](), our source iterable can be formatted/transformed to fit like so:
445+
By using [`iterateFormatted`](#iterateformatted), our source iterable can be formatted/transformed to fit like so:
442446

443447
```tsx
444448
const currenciesIter = getAvailableCurrenciesIter();
@@ -484,8 +488,8 @@ function MyComponent() {
484488
}
485489
```
486490

487-
> <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/>
489493
490494

491495

@@ -495,9 +499,9 @@ So unless you require some more elaborate transformation than simply formatting
495499

496500
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.
497501

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.
499503

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.
501505

502506
In a glance, it's usage looks like this:
503507

@@ -823,12 +827,12 @@ It's similar to [`<It>`](#it), only it works with any changeable number of async
823827
yield `Item ${i}`;
824828
}
825829
})();
826-
setInputs(prev => [...prev, iterableValue]);
830+
setInputs(prev => [iterableValue, ...prev]);
827831
};
828832

829833
const addStaticValue = () => {
830834
const staticValue = `Static ${inputs.length + 1}`;
831-
setInputs(prev => [...prev, staticValue]);
835+
setInputs(prev => [staticValue, ...prev]);
832836
};
833837

834838
return (

0 commit comments

Comments
 (0)