react-async-ui
Version:
Asynchronous React hooks to manage modal UI state
95 lines (69 loc) • 3.41 kB
Markdown
# react-async-ui
[](https://www.npmjs.com/package/react-async-ui)


This package provides state management primitives to build modal user interactions that you can `await`, `resolve` and `reject` using a familiar, `Promise`-based API.
### Design goals
- Provide lightweight building blocks to express modal UI _behavior_ as `async`/`await` workflows
- Provide a *headless* hooks-based API that keeps you flexible in your choice of UI component library and styling solution
- Provide first-class TypeScript support and documentation
### Installation
```sh
npm install react-async-ui
```
## API
The _react-async-ui_ package exports the `useAsyncModalState` hook to manage the lifecycle of a modal UI element that can be shown, `await`'ed, and can optionally accept parameters and return a result to the caller.
```ts
const [state, showModal] = useAsyncModalState<TValue, TResult>()
```
Similar to React's `setState` hook, it returns an array with exactly two elements:
- `state`: Represents the current interaction state. This object has the following properties:
| Name | Description |
| ---- | ----------- |
| `isOpen` | `true` if the modal is open, `false` otherwise |
| `props` | (Only available when `isOpen` is `true`) |
| `props.value` | The (optional) parameter passed to `showModal()` |
| `props.resolve()` | Completes the modal interaction. Takes an optional `result` parameter that will be returned from `showModal()`. |
| `props.reject()` | Fails the modal interaction with an exception. Takes an optional `reason` parameter that will be thrown from `showModal()`. |
- `showModal()`: A callback to open the modal and optionally pass along a parameter value. It returns a `Promise` object, so you can `await` it to obtain the result of the modal interaction when the modal component calls `state.props.{resolve|reject}`:
```ts
const result = await showModal(42)
```
## Example
Let's build a simple greeter dialog that takes a single string argument (i.e., the name of the person to greet) and can be dismissed through "OK" and "Cancel" buttons:
```tsx
import { useAsyncModalState } from 'react-async-ui'
function App() {
// Declare state for a modal interaction that takes a string
// argument and completes with either 'ok' or 'cancel'
const [state, showModal] = useAsyncModalState<string, 'ok' | 'cancel'>()
const sayHello = async () => {
const result = await showModal('world')
if (result === 'ok') {
// TODO: Handle "ok" result
}
}
return (
<>
<button onClick={sayHello}>
Say hello!
</button>
{/* Only render dialog when state says it's open */}
{state.isOpen && <GreeterDialog {...state.props} />}
</>
)
}
```
The corresponding dialog component then uses `state.props` to access the passed value and return a result through `showModal`:
```tsx
import { AsyncModalProps } from 'react-async-ui'
function GreeterDialog({ value, resolve }: AsyncModalProps<string, 'ok' | 'cancel'>) {
return (
<dialog open>
<p>Hello, {value}!</p>
<button onClick={() => resolve('ok')}> OK </button>
<button onClick={() => resolve('cancel')}> Cancel </button>
</dialog>
)
}
```