EN
React - custom useFetch hook
9
points
I this article we would like to show how to create own one useFetch
hook in React.
Main adwantage of using fetch hooks is preventing against state updating when component is unmount, what happens when we use AJAX requests that update unmount components - AJAX requests are async (by default). The solution for the problem is to monitor mount state with useRef
and ignore AJAX
response when component is in unmount state.
Practical example:
// ONLINE-RUNNER:browser;
//import React from 'react';
//import ReactDOM from 'react-dom';
const useFetch = (url, options) => {
const mountRef = React.useRef(false);
const [status, setStatus] = React.useState();
const [response, setResponse] = React.useState();
React.useEffect(() => {
setStatus('loading');
const setSuccess = (responseData) => {
if (!mountRef.current) return; // updating only on mount component
setStatus('success');
setResponse(responseData);
};
const setFailed = () => {
if (!mountRef.current) return; // updates only on mount component
setStatus('failed');
};
mountRef.current = true; // setting component mount flag to true
fetch(url, options)
.then(response => {
if (!mountRef.current) return; // updates only on mount component
// we want to recive text response
response.text()
.then(setSuccess)
.catch(setFailed);
})
.catch(setFailed);
return () => {
mountRef.current = false; // setting component mount flag to false
};
}, [url, options]);
// status: loading, success, failed
return [status, response];
};
const App = () => {
const [status, response] = useFetch('/examples/echo?text=Hello');
return (
<div>
<div>status: {status}</div>
{status === 'success' && <div>response: {response}</div>}
</div>
);
};
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);
useFetch
with multiple components
In this example we would like to show why useFetch is very useful with components - with one line we are able to add data fetching.
// ONLINE-RUNNER:browser;
//import React from 'react';
//import ReactDOM from 'react-dom';
const useFetch = (url, options) => {
const mountRef = React.useRef(false);
const [status, setStatus] = React.useState();
const [response, setResponse] = React.useState();
React.useEffect(() => {
setStatus('loading');
const setSuccess = (responseData) => {
if (!mountRef.current) return;
setStatus('success');
setResponse(responseData);
};
const setFailed = () => {
if (!mountRef.current) return;
setStatus('failed');
};
mountRef.current = true;
fetch(url, options)
.then(response => {
if (!mountRef.current) return;
response.text()
.then(setSuccess)
.catch(setFailed);
})
.catch(setFailed);
return () => {
mountRef.current = false;
};
}, [url, options]);
// status: loading, success, failed
return [status, response];
};
const Hello = ({hello}) => {
const safeHelloProp = encodeURIComponent(hello);
const [status, response] = useFetch(`/examples/echo?text=${safeHelloProp}`);
return (
<div>
{status === 'success' && <>response: {response}</>}
</div>
);
};
const App = () => {
const [status, response] = useFetch('/examples/echo?text=Hello');
return (
<div>
<Hello hello="Hi!" />
<Hello hello="Welcome!" />
<Hello hello="Good morning!" />
</div>
);
};
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);