Skip to content

Commit 93c7cbd

Browse files
committed
Setup gitbook.
1 parent edad9f5 commit 93c7cbd

File tree

7 files changed

+771
-0
lines changed

7 files changed

+771
-0
lines changed

.gitbook.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
root: ./gitbook/
2+
3+
structure:
4+
readme: introduction.md
5+
summary: _summary.md

gitbook/1.introduction.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Introduction
2+
3+
React Async is a utility belt for declarative promise resolution and data fetching. It makes it easy to handle
4+
asynchronous UI states, without assumptions about the shape of your data or the type of request. React Async consists of
5+
a React component and several hooks. You can use it with `fetch`, Axios or other data fetching libraries, even GraphQL.
6+
7+
## Rationale
8+
9+
React Async is different in that it tries to resolve data as close as possible to where it will be used, while using
10+
declarative syntax, using just JSX and native promises. This is in contrast to systems like Redux where you would
11+
configure any data fetching or updates on a higher (application global) level, using a special construct
12+
(actions/reducers).
13+
14+
React Async works well even in larger applications with multiple or nested data dependencies. It encourages loading
15+
data on-demand and in parallel at component level instead of in bulk at the route/page level. It's entirely decoupled
16+
from your routes, so it works well in complex applications that have a dynamic routing model or don't use routes at all.
17+
18+
React Async is promise-based, so you can resolve anything you want, not just `fetch` requests.
19+
20+
## Concurrent React and Suspense
21+
22+
The React team is currently working on a large rewrite called [Concurrent React], previously known as "Async React".
23+
Part of this rewrite is Suspense, which is a generic way for components to suspend rendering while they load data from
24+
a cache. It can render a fallback UI while loading data, much like `<Async.Pending>`.
25+
26+
React Async has no direct relation to Concurrent React. They are conceptually close, but not the same. React Async is
27+
meant to make dealing with asynchronous business logic easier. Concurrent React will make those features have less
28+
impact on performance and usability. When Suspense lands, React Async will make full use of Suspense features. In fact,
29+
you can already **start using React Async right now**, and in a later update, you'll **get Suspense features for free**.
30+
In fact, React Async already has experimental support for Suspense, by passing the `suspense` option.
31+
32+
[concurrent react]: https://github.com/sw-yx/fresh-concurrent-react/blob/master/Intro.md#introduction-what-is-concurrent-react

gitbook/2.installation.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Getting started
2+
3+
You can install `react-async` from npm:
4+
5+
```
6+
npm install --save react-async
7+
```
8+
9+
Or if you're using Yarn:
10+
11+
```
12+
yarn add react-async
13+
```
14+
15+
> This package requires `react` as a peer dependency. Please make sure to install that as well.
16+
> If you want to use the `useAsync` hook, you'll need `[email protected]` or later.
17+
18+
## Upgrading
19+
20+
### Upgrade to v8
21+
22+
All standalone helper components were renamed to avoid import naming collision.
23+
24+
- `<Initial>` was renamed to `<IfInitial>`.
25+
- `<Pending>` was renamed to `<IfPending>`.
26+
- `<Fulfilled>` was renamed to `<IfFulfilled>`.
27+
- `<Rejected>` was renamed to `<IfRejected`.
28+
- `<Settled>` was renamed to `<IfSettled>`.
29+
30+
> A [codemod](https://github.com/async-library/react-async/tree/master/codemods) is available to automate the upgrade.
31+
32+
The return type for `run` was changed from `Promise` to `undefined`. You should now use the `promise` prop instead. This
33+
is a manual upgrade. See [`promise`](#promise-1) for details.
34+
35+
### Upgrade to v6
36+
37+
- `<Async.Pending>` was renamed to `<Async.Initial>`.
38+
- Some of the other helpers were also renamed, but the old ones remain as alias.
39+
- Don't forget to deal with any custom instances of `<Async>` when upgrading.
40+
41+
> A [codemod](https://github.com/async-library/react-async/tree/master/codemods) is available to automate the upgrade.
42+
43+
### Upgrade to v4
44+
45+
- `deferFn` now receives an `args` array as the first argument, instead of arguments to `run` being spread at the front
46+
of the arguments list. This enables better interop with TypeScript. You can use destructuring to keep using your
47+
existing variables.
48+
- The shorthand version of `useAsync` now takes the `options` object as optional second argument. This used to be
49+
`initialValue`, but was undocumented and inflexible.

gitbook/3.usage.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Usage
2+
3+
React Async offers three primary APIs: the `useAsync` hook, the `<Async>` component and the `createInstance`
4+
factory function. Each has its unique benefits and downsides.
5+
6+
## As a hook
7+
8+
The `useAsync` hook (available [from React v16.8.0](https://reactjs.org/hooks)) offers direct access to React Async's
9+
core functionality from within your own function components:
10+
11+
```jsx
12+
import { useAsync } from "react-async"
13+
14+
const loadCustomer = async ({ customerId }, { signal }) => {
15+
const res = await fetch(`/api/customers/${customerId}`, { signal })
16+
if (!res.ok) throw new Error(res)
17+
return res.json()
18+
}
19+
20+
const MyComponent = () => {
21+
const { data, error, isPending } = useAsync({ promiseFn: loadCustomer, customerId: 1 })
22+
if (isPending) return "Loading..."
23+
if (error) return `Something went wrong: ${error.message}`
24+
if (data)
25+
return (
26+
<div>
27+
<strong>Loaded some data:</strong>
28+
<pre>{JSON.stringify(data, null, 2)}</pre>
29+
</div>
30+
)
31+
return null
32+
}
33+
```
34+
35+
> Using [helper components](#with-helper-components) can greatly improve readability of your render functions by not
36+
> having to write all those conditional returns.
37+
38+
Or using the shorthand version:
39+
40+
```jsx
41+
const MyComponent = () => {
42+
const { data, error, isPending } = useAsync(loadCustomer, options)
43+
// ...
44+
}
45+
```
46+
47+
### With `useFetch`
48+
49+
Because fetch is so commonly used with `useAsync`, there's a dedicated `useFetch` hook for it:
50+
51+
```jsx
52+
import { useFetch } from "react-async"
53+
54+
const MyComponent = () => {
55+
const headers = { Accept: "application/json" }
56+
const { data, error, isPending, run } = useFetch("/api/example", { headers }, options)
57+
// This will setup a promiseFn with a fetch request and JSON deserialization.
58+
59+
// you can later call `run` with an optional callback argument to
60+
// last-minute modify the `init` parameter that is passed to `fetch`
61+
function clickHandler() {
62+
run(init => ({
63+
...init,
64+
headers: {
65+
...init.headers,
66+
authentication: "...",
67+
},
68+
}))
69+
}
70+
71+
// alternatively, you can also just use an object that will be spread over `init`.
72+
// please note that this is not deep-merged, so you might override properties present in the
73+
// original `init` parameter
74+
function clickHandler2() {
75+
run({ body: JSON.stringify(formValues) })
76+
}
77+
}
78+
```
79+
80+
`useFetch` takes the same arguments as [fetch] itself, as well as `options` to the underlying `useAsync` hook. The
81+
`options` object takes two special boolean properties: `defer` and `json`. These can be used to switch between
82+
`deferFn` and `promiseFn`, and enable JSON parsing. By default `useFetch` automatically uses `promiseFn` or `deferFn`
83+
based on the request method (`deferFn` for POST / PUT / PATCH / DELETE) and handles JSON parsing if the `Accept` header
84+
is set to `"application/json"`.
85+
86+
[fetch]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
87+
88+
## As a component
89+
90+
The classic interface to React Async. Simply use `<Async>` directly in your JSX component tree, leveraging the render
91+
props pattern:
92+
93+
```jsx
94+
import Async from "react-async"
95+
96+
// Your promiseFn receives all props from Async and an AbortController instance
97+
const loadCustomer = ({ customerId }, { signal }) =>
98+
fetch(`/api/customers/${customerId}`, { signal })
99+
.then(res => (res.ok ? res : Promise.reject(res)))
100+
.then(res => res.json())
101+
102+
const MyComponent = () => (
103+
<Async promiseFn={loadCustomer} customerId={1}>
104+
{({ data, error, isPending }) => {
105+
if (isPending) return "Loading..."
106+
if (error) return `Something went wrong: ${error.message}`
107+
if (data)
108+
return (
109+
<div>
110+
<strong>Loaded some data:</strong>
111+
<pre>{JSON.stringify(data, null, 2)}</pre>
112+
</div>
113+
)
114+
return null
115+
}}
116+
</Async>
117+
)
118+
```
119+
120+
> Using [helper components](#with-helper-components) can greatly improve readability of your render functions by not
121+
> having to write all those conditional returns.
122+
123+
## As a factory
124+
125+
You can also create your own component instances, allowing you to preconfigure them with options such as default
126+
`onResolve` and `onReject` callbacks.
127+
128+
```jsx
129+
import { createInstance } from "react-async"
130+
131+
const loadCustomer = ({ customerId }, { signal }) =>
132+
fetch(`/api/customers/${customerId}`, { signal })
133+
.then(res => (res.ok ? res : Promise.reject(res)))
134+
.then(res => res.json())
135+
136+
// createInstance takes a defaultProps object and a displayName (both optional)
137+
const AsyncCustomer = createInstance({ promiseFn: loadCustomer }, "AsyncCustomer")
138+
139+
const MyComponent = () => (
140+
<AsyncCustomer customerId={1}>
141+
<AsyncCustomer.Fulfilled>{customer => `Hello ${customer.name}`}</AsyncCustomer.Fulfilled>
142+
</AsyncCustomer>
143+
)
144+
```
145+
146+
## With helper components
147+
148+
Several [helper components](#helper-components) are available to improve legibility. They can be used with `useAsync`
149+
by passing in the state, or with `<Async>` by using Context. Each of these components simply enables or disables
150+
rendering of its children based on the current state.
151+
152+
```jsx
153+
import { useAsync, IfPending, IfFulfilled, IfRejected } from "react-async"
154+
155+
const loadCustomer = async ({ customerId }, { signal }) => {
156+
// ...
157+
}
158+
159+
const MyComponent = () => {
160+
const state = useAsync({ promiseFn: loadCustomer, customerId: 1 })
161+
return (
162+
<>
163+
<IfPending state={state}>Loading...</IfPending>
164+
<IfRejected state={state}>{error => `Something went wrong: ${error.message}`}</IfRejected>
165+
<IfFulfilled state={state}>
166+
{data => (
167+
<div>
168+
<strong>Loaded some data:</strong>
169+
<pre>{JSON.stringify(data, null, 2)}</pre>
170+
</div>
171+
)}
172+
</IfFulfilled>
173+
</>
174+
)
175+
}
176+
```
177+
178+
### As compounds to `<Async>`
179+
180+
Each of the helper components are also available as static properties of `<Async>`. In this case you won't have to pass
181+
the state object, instead it will be automatically provided through Context.
182+
183+
```jsx
184+
import Async from "react-async"
185+
186+
const loadCustomer = ({ customerId }, { signal }) =>
187+
fetch(`/api/customers/${customerId}`, { signal })
188+
.then(res => (res.ok ? res : Promise.reject(res)))
189+
.then(res => res.json())
190+
191+
const MyComponent = () => (
192+
<Async promiseFn={loadCustomer} customerId={1}>
193+
<Async.Pending>Loading...</Async.Pending>
194+
<Async.Fulfilled>
195+
{data => (
196+
<div>
197+
<strong>Loaded some data:</strong>
198+
<pre>{JSON.stringify(data, null, 2)}</pre>
199+
</div>
200+
)}
201+
</Async.Fulfilled>
202+
<Async.Rejected>{error => `Something went wrong: ${error.message}`}</Async.Rejected>
203+
</Async>
204+
)
205+
```

0 commit comments

Comments
 (0)