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.
// function reference storing
const callbackRef = React.useRef();
callbackRef.current = () => { // for each rendering cycle we set current one function
// some code here ...
};
// stored function calling
callbackRef.current?.();
Note: read this article to see how to create custom
useCurrentCallback
hook.
Practical solution:
// ONLINE-RUNNER:browser;
//import React from 'react';
//import ReactDOM from 'react-dom';
const App = () => {
const callbackRef = React.useRef();
const [counter, setCounter] = React.useState(0);
callbackRef.current = () => {
setCounter(counter + 1);
};
React.useEffect(() => {
const handle = setInterval(() => {
callbackRef.current?.();
}, 100);
return () => clearInterval(handle);
}, []);
return (
<div>counter: {counter}</div>
);
};
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);
Component without actual function reference
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.
// ONLINE-RUNNER:browser;
//import React from 'react';
//import ReactDOM from 'react-dom';
const App = () => {
const [counter, setCounter] = React.useState(0);
const callback = () => {
setCounter(counter + 1);
};
React.useEffect(() => {
const handle = setInterval(() => callback(), 100);
return () => clearInterval(handle);
}, []);
return (
<div>counter: {counter}</div>
);
};
const root = document.querySelector('#root');
ReactDOM.render(<App />, root);