EN
React - use current callback
5 points
In this short article we would like to show how in React
use always current reference to some callback.
As current callback reference we understand: using same function between component rendeinrg cycles. The solution is to use useRef
hook to store function reference.
xxxxxxxxxx
1
// function reference storing
2
const callbackRef = React.useRef();
3
callbackRef.current = () => { // for each rendering cycle we set current one function
4
// some code here ...
5
};
6
7
// stored function calling
8
callbackRef.current?.();
Note: read this article to see how to create custom
useCurrentCallback
hook.
Practical solution:
xxxxxxxxxx
1
//import React from 'react';
2
//import ReactDOM from 'react-dom';
3
4
const App = () => {
5
const callbackRef = React.useRef();
6
const [counter, setCounter] = React.useState(0);
7
callbackRef.current = () => {
8
setCounter(counter + 1);
9
};
10
React.useEffect(() => {
11
const handle = setInterval(() => {
12
callbackRef.current?.();
13
}, 100);
14
return () => clearInterval(handle);
15
}, []);
16
return (
17
<div>counter: {counter}</div>
18
);
19
};
20
21
const root = document.querySelector('#root');
22
ReactDOM.render(<App />, root);
This section presents case what if we could do not use useRef
to store function reference.
The issue of below example is: the counter is not incremented in right way, because calback
reference used inside setInterval(...)
indicates function from first rendering cycle.
xxxxxxxxxx
1
//import React from 'react';
2
//import ReactDOM from 'react-dom';
3
4
const App = () => {
5
const [counter, setCounter] = React.useState(0);
6
const callback = () => {
7
setCounter(counter + 1);
8
};
9
React.useEffect(() => {
10
const handle = setInterval(() => callback(), 100);
11
return () => clearInterval(handle);
12
}, []);
13
return (
14
<div>counter: {counter}</div>
15
);
16
};
17
18
const root = document.querySelector('#root');
19
ReactDOM.render(<App />, root);