Update and rename UseAsync.md to useAsync.md
This commit is contained in:
@ -1,73 +0,0 @@
|
|||||||
---
|
|
||||||
title: useAsync
|
|
||||||
tags: hooks,state,effect,intermediate
|
|
||||||
---
|
|
||||||
|
|
||||||
A hook that handles asynchronous calls.
|
|
||||||
|
|
||||||
- Create a custom hook that takes a handler `function` and `options`.
|
|
||||||
- Use the `React.useState()` hook to initialize the `value`, `error` and `loading` state variables.
|
|
||||||
- Use the `React.useEffect()` hook to call `run()` method and update the state variables accordingly if `options.autoRun` set to true.
|
|
||||||
- Use the `run` function to manually trigger `handler` function.
|
|
||||||
- Return an object containting the `value`, `error` and `isLoading` state variables and `run` function.
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
const useAsync = (fn, options = {}) => {
|
|
||||||
const [value, setValue] = React.useState(null);
|
|
||||||
const [error, setError] = React.useState(null);
|
|
||||||
const [isLoading, setIsLoading] = React.useState(false);
|
|
||||||
|
|
||||||
const autoRun = options.autoRun || false;
|
|
||||||
|
|
||||||
const run = async (args = null) => {
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
const value = await fn(args);
|
|
||||||
setIsLoading(false);
|
|
||||||
setError(null);
|
|
||||||
setValue(value);
|
|
||||||
} catch (error) {
|
|
||||||
setIsLoading(false);
|
|
||||||
setError(error);
|
|
||||||
setValue(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (autoRun) {
|
|
||||||
run();
|
|
||||||
}
|
|
||||||
}, [autoRun]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
value,
|
|
||||||
error,
|
|
||||||
isLoading,
|
|
||||||
run,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
const App = () => {
|
|
||||||
const handleSubmit = args => {
|
|
||||||
// args { foo: bar }
|
|
||||||
const url = "https://jsonplaceholder.typicode.com/todos";
|
|
||||||
return fetch(url).then(response => response.json());
|
|
||||||
};
|
|
||||||
|
|
||||||
const submission = useAsync(handleSubmit, { autoRun: false });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
onClick={() => submission.run({ foo: "bar" })}
|
|
||||||
disabled={submission.isLoading}
|
|
||||||
>
|
|
||||||
{submission.isLoading ? "Loading..." : "click me"}
|
|
||||||
</button>
|
|
||||||
<pre>{JSON.stringify(submission.value, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
65
snippets/useAsync.md
Normal file
65
snippets/useAsync.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
title: useAsync
|
||||||
|
tags: hooks,state,reducer,advanced
|
||||||
|
---
|
||||||
|
|
||||||
|
A hook that handles asynchronous calls.
|
||||||
|
|
||||||
|
- Create a custom hook that takes a handler function, `fn`.
|
||||||
|
- Define a reducer function and an initial state for the custom hook's state.
|
||||||
|
- Use the `React.useReducer()` hook to initialize the `state` variable and the `dispatch` function.
|
||||||
|
- Define a `run` function that will run the provided callback, `fn`, while using `dispatch` to update `state` as necessary.
|
||||||
|
- Return an object containting the the properties of `state` (`value`, `error` and `loading`) and the `run` function.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const useAsync = (fn) => {
|
||||||
|
const initialState = { loading: false, error: null, value: null };
|
||||||
|
const stateReducer = (_, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'start':
|
||||||
|
return { loading: true, error: null, value: null};
|
||||||
|
case 'finish':
|
||||||
|
return { loading: false, error: null, value: action.value};
|
||||||
|
case 'error':
|
||||||
|
return { loading: false, error: action.error, value: null};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [state, dispatch] = React.useReducer(stateReducer, initialState);
|
||||||
|
|
||||||
|
const run = async (args = null) => {
|
||||||
|
try {
|
||||||
|
dispatch({ type: 'start' });
|
||||||
|
const value = await fn(args);
|
||||||
|
dispatch({ type: 'finish', value });
|
||||||
|
} catch (error) {
|
||||||
|
dispatch({ type: 'error', error });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...state, run };
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const RandomImage = props => {
|
||||||
|
const imgFetch = useAsync(url => fetch(url).then(response => response.json()));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() => imgFetch.run('https://dog.ceo/api/breeds/image/random')}
|
||||||
|
disabled={ imgFetch.isLoading }
|
||||||
|
>
|
||||||
|
Load image
|
||||||
|
</button>
|
||||||
|
<br/>
|
||||||
|
{ imgFetch.loading && <div>Loading...</div> }
|
||||||
|
{ imgFetch.error && <div>Error { imgFetch.error }</div> }
|
||||||
|
{ imgFetch.value && <img src={ imgFetch.value.message } alt="avatar" width={400} height="auto" />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ReactDOM.render(<RandomImage />, document.getElementById('root'));
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user