T8 React Pending
Example
Objective: Track the pending state of the async fetchItems()
action to tell the user whether the UI is busy or encountered an error (preferably without rewriting the action and the app's state management).
+ import { usePendingState } from "@t8/react-pending";
export const ItemList = () => {
const [items, setItems] = useState([]);
+ const [state, withState] = usePendingState("fetch-items");
useEffect(() => {
- fetchItems().then(setItems);
+ withState(fetchItems()).then(setItems);
}, [fetchItems, withState]);
+ if (!state.complete) return <p>Loading...</p>;
+ if (state.error) return <p>An error occurred</p>;
return <ul>{items.map(/* ... */)}</ul>;
};
+ import { usePendingState } from "@t8/react-pending";
export const Status = () => {
+ const [state] = usePendingState("fetch-items");
if (!state.initialized) return "";
if (!state.complete) return "Busy";
if (state.error) return "Error";
return "OK";
};
🔹 In this example, the action's value (the items
array) is stored in the component's local state, but it can be stored in any app state of the developer's choice.
Shared and local pending state
Omit the custom string key parameter of usePendingState()
to scope the pending state locally within a single component:
- const [state, withState] = usePendingState("fetch-items"); // shared
+ const [state, withState] = usePendingState(); // local
Silent tracking of background and optimistic updates
- withState(fetchItems())
+ withState(fetchItems(), { silent: true })
🔹 This option prevents state.complete
from switching to false
in the pending state.
Delayed pending state
- withState(fetchItems())
+ withState(fetchItems(), { delay: 500 })
🔹 Use case: avoiding flashing a process indicator when the action is likely to complete by the end of a short delay.
Custom rejection handler
- withState(fetchItems())
+ withState(fetchItems(), { throws: true }).catch(handleError)
🔹 This option allows the async action to reject explicitly, along with exposing state.error
that goes by default.
Providing blank initial pending state
+ import { PendingStateProvider } from "@t8/react-pending";
- <App/>
+ <PendingStateProvider>
+ <App/>
+ </PendingStateProvider>
🔹 <PendingStateProvider>
creates an isolated instance of initial shared action state. Prime use cases: tests, SSR. It isn't required with client-side rendering, but it can be used to separate action states of larger self-contained portions of a web app.
Providing custom initial pending state
+ const initialState = {
+ "fetch-items": { initialized: true, complete: true },
+ };
- <PendingStateProvider>
+ <PendingStateProvider value={initialState}>
<App/>
</PendingStateProvider>
🔹 While fully optional, this setup allows to override the initial state received from usePendingState(stateKey)
.
🔹 With an explicit value or without, the <PendingStateProvider>
's nested components will only respond to updates in the particular action states they subscribed to by means of usePendingState(stateKey)
.