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:
xxxxxxxxxx
1
//import React from 'react';
2
//import ReactDOM from 'react-dom';
3
4
const useFetch = (url, options) => {
5
const mountRef = React.useRef(false);
6
const [status, setStatus] = React.useState();
7
const [response, setResponse] = React.useState();
8
React.useEffect(() => {
9
setStatus('loading');
10
const setSuccess = (responseData) => {
11
if (!mountRef.current) return; // updating only on mount component
12
setStatus('success');
13
setResponse(responseData);
14
};
15
const setFailed = () => {
16
if (!mountRef.current) return; // updates only on mount component
17
setStatus('failed');
18
};
19
mountRef.current = true; // setting component mount flag to true
20
fetch(url, options)
21
.then(response => {
22
if (!mountRef.current) return; // updates only on mount component
23
// we want to recive text response
24
response.text()
25
.then(setSuccess)
26
.catch(setFailed);
27
})
28
.catch(setFailed);
29
return () => {
30
mountRef.current = false; // setting component mount flag to false
31
};
32
}, [url, options]);
33
// status: loading, success, failed
34
return [status, response];
35
};
36
37
const App = () => {
38
const [status, response] = useFetch('/examples/echo?text=Hello');
39
return (
40
<div>
41
<div>status: {status}</div>
42
{status === 'success' && <div>response: {response}</div>}
43
</div>
44
);
45
};
46
47
const root = document.querySelector('#root');
48
ReactDOM.render(<App />, root);
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.
xxxxxxxxxx
1
//import React from 'react';
2
//import ReactDOM from 'react-dom';
3
4
const useFetch = (url, options) => {
5
const mountRef = React.useRef(false);
6
const [status, setStatus] = React.useState();
7
const [response, setResponse] = React.useState();
8
React.useEffect(() => {
9
setStatus('loading');
10
const setSuccess = (responseData) => {
11
if (!mountRef.current) return;
12
setStatus('success');
13
setResponse(responseData);
14
};
15
const setFailed = () => {
16
if (!mountRef.current) return;
17
setStatus('failed');
18
};
19
mountRef.current = true;
20
fetch(url, options)
21
.then(response => {
22
if (!mountRef.current) return;
23
response.text()
24
.then(setSuccess)
25
.catch(setFailed);
26
})
27
.catch(setFailed);
28
return () => {
29
mountRef.current = false;
30
};
31
}, [url, options]);
32
// status: loading, success, failed
33
return [status, response];
34
};
35
36
const Hello = ({hello}) => {
37
const safeHelloProp = encodeURIComponent(hello);
38
const [status, response] = useFetch(`/examples/echo?text=${safeHelloProp}`);
39
return (
40
<div>
41
{status === 'success' && <>response: {response}</>}
42
</div>
43
);
44
};
45
46
const App = () => {
47
const [status, response] = useFetch('/examples/echo?text=Hello');
48
return (
49
<div>
50
<Hello hello="Hi!" />
51
<Hello hello="Welcome!" />
52
<Hello hello="Good morning!" />
53
</div>
54
);
55
};
56
57
const root = document.querySelector('#root');
58
ReactDOM.render(<App />, root);