Releases: stegano/react-render-state-hook
v1.2.4
v1.2.3
v1.2.2
v1.2.0
Features
- feat(store): add
debug
option - feat(contexts): add
store
property toRenderSateProvider
Fixes
- fix(store): add
initialStore
option
BREAKING CHANGES
-
fix(providers): rename the
dataHandlerExecutorInterceptors
option todataHandlerExecutorInterceptorList
-
fix(store): change
middleware
interface return type// Before export interface Middleware<Data, Dataset = Record<string, Data>> { (id: string, next: Data, store: Dataset): { id: string; data: Data } | undefined; } // After export interface Middleware<Data, Dataset = Record<string, Data>> { (id: string, next: Data, store: Dataset): Data; }
v1.1.1
v1.1.0
Features
- feat(hooks): add
DataResetHandler
function - feat(hooks): add
Idle
status
Refactors
- refactor(hooks): rename interfaces and add descriptions
- refactor(hooks): rename
DataHandleStatus
BREAKING CHANGES
-
The DataHandlingStatus enum values have been modified. Please refer to the code snippet below:
// Before export enum DataHandlingStatus { IN_PROGRESS = "IN_PROGRESS", SUCCEEDED = "SUCCEEDED", FAILED = "FAILED", } // After export enum DataHandlingStatus { IDLE = "IDLE", IN_PROGRESS = "IN_PROGRESS", COMPLETED = "COMPLETED", FAILURE = "FAILURE", }
-
With the addition of DataResetHandler, the return value of the useRenderState hook has been changed. Please refer to the code snippet below:
// Before const [render, handleData, state] = useRenderState(...); // After const [render, handleData, handleDataReset, state] = useRenderState(...);
-
Due to the addition of the Idle state, the render argument has been modified. Please refer to the code snippet below:
const [render] = useRenderState(...); ... // Before return render("Completed", "Loading", "Failure"); // After return render("Completed", "Idle", "Loading", "Failure");
v1.0.0
React Render State Hook
React Render State Hook: This hook allows you to declaratively define components that will be rendered based on the data processing state.
Installation
The easiest way to install react-render-state-hook
is with npm.
npm install react-render-state-hook
Alternately, download the source.
git clone https://github.com/stegano/react-render-state-hook.git
Quick Start
Basic
The useRenderState
hook enables a declarative approach to display components based on data processing status.
import { useState, useCallback } from "react";
import { useRenderState } from "react-render-state-hook";
export const App = () => {
const [render, handleData] = useRenderState<string, Error>();
// When this function is invoked, it generates and returns a random string after 3 seconds.
const updateRandomString = useCallback(
() =>
new Promise<string>((resolve) => {
const randomString = Math.random().toString(32).slice(2);
setTimeout(() => resolve(randomString), 1000 * 3);
}),
[],
);
useEffect(() => {
// When the component is first rendered, it updates a random string.
handleData(async () => updateRandomString());
}, [updateRandomString, handleData]);
const handleButtonClick = useCallback(() => {
// When the button is clicked, it updates a random string.
handleData(async () => updateRandomString());
}, [updateRandomString, handleData]);
// Use `render` function to define rendering for data processing statuses: succeeded, in-progress, or failed. It auto-renders based on the `handleData` function's processing status.
return render(
(data) => (
<div>
<p>Succeeded({data})</p>
<button type="button" onClick={handleButtonClick}>
Update
</button>
</div>
),
<p>Loading..</p>,
(error) => <p>Error, Oops something went wrong.. :(, ({error.message})</p>,
);
};
Demo: https://stackblitz.com/edit/stackblitz-starters-pgefl6
Sharing Rendering Data
It is possible to share data and rendering state among multigitple containers(components).
import { useState, useCallback } from "react";
import { useRenderState } from "react-render-state-hook";
export const ComponentA = () => {
const [render, handleData] = useRenderState<string, Error>(
undefined,
"randomString" // By providing a data sharing key, you can share data processing state and values.
);
const updateRandomString = useCallback(
() =>
new Promise<string>((resolve) => {
const randomString = Math.random().toString(32).slice(2);
setTimeout(() => resolve(randomString), 1000 * 3);
}),
[],
);
useEffect(() => {
handleData(async () => updateRandomString());
}, [updateRandomString, handleData]);
return render(
(data) => (
<div>
<p>Succeeded({data})</p>
</div>
),
<p>Loading..</p>,
(error) => <p>Error, Oops something went wrong.. :(, ({error.message})</p>,
);
};
export const ComponentB = () => {
const [render] = useRenderState<string, Error>(
undefined,
"randomString" // By providing a data sharing key, you can share data processing state and values.
);
// While this component does not directly handle the data, the rendering data state is updated by ComponentA.
return render(
(data) => (
<div>
<p>Succeeded({data})</p>
</div>
),
<p>Loading..</p>,
(error) => <p>Error, Oops something went wrong.. :(, ({error.message})</p>,
);
};
export const App = () => {
return (
<>
<ComponentA />
<ComponentB />
</>
)
};
🧐 Advanced features
dataHandlerExecutorInterceptors
dataHandlerExecutorInterceptors
can intercept dataHandlerExecutor
execution, allowing you to transform it. It can be useful for adding logs for data processing or injecting dummy data for use in Storybook and testing environments.
import { useCallback, useEffect } from 'react';
import {
RenderStateProvider,
useRenderState,
} from 'react-render-state-hook';
const Component = () => {
const generateGreetingMessage = useCallback(async () => {
// e.g., asynchronous processing tasks like `return (await axios.get('.../data.json')).data.greeting;` are also possible.
return 'Hi';
}, []);
const [render, handleData] = useRenderState<string>();
useEffect(() => {
handleData(async () => {
const greeting = await generateGreetingMessage();
return greeting;
},
'greeting' // 'greeting' is the executorId. This value serves as an identifier in `dataHandlerExecutorInterceptors` to distinguish tasks.
);
}, [handleData]);
return render((greeting) => <p>{greeting}</p>);
};
export const App = ({ children }) => {
return (
<RenderStateProvider
dataHandlerExecutorInterceptors={[
async (_previousInterceptorResult, dataHandlerExecutor, executorId) => {
if (executorId === 'greeting') {
// The `dataHandlerExecutor` with an executorId value of 'greeting' is not actually executed instead, this provider returns the value 'Hello'.
return 'Hello';
}
return await dataHandlerExecutor();
}
]}
>
<Component />
</RenderStateProvider>
);
};
Demo: https://stackblitz.com/edit/stackblitz-starters-4qxzui