I have a very simple React App create using create-react-app. The app displays a single component passing in a value and an onClick callback and incrementshe value when the callback is triggered.
import React, { useState } from 'react';
import Block from './Block';
const App = () => {
const [count, setCount] = useState(0)
return (
<div className="App">
<Block
value={count}
onClick={ () => setCount(count + 1) }
/>
</div>
);
}
export default App;
The Block component takes a value and a onClick function and displays a square with the value in the centre and calls the onClick whenever the square is clicked.
const Block = ({ value, onClick }) => {
return (
<div
onClick={onClick}
style={{
width: 200,
height: 200,
margin: 50,
background: 'yellow',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
fontSize: 36,
}}
>
{value}
</div>
);
}
export default Block;
This works excatly as described.
I have then extended this component to log the value on a mouseenter and mouseleave event by adding the relevent event handlers in a useEffect hook called when the component mounts.
import React, { useEffect, useRef } from 'react';
const Block = ({ value, onClick }) => {
const divRef = useRef();
const mouseEnter = () => {
console.log('mouse enter', value);
}
const mouseLeave = () => {
console.log('mouse leave', value);
}
useEffect(() => {
console.log('addEventListeners');
divRef.current.addEventListener('mouseenter', mouseEnter);
divRef.current.addEventListener('mouseleave', mouseLeave);
}, [])
return (
<div
ref={divRef}
onClick={onClick}
style={{
width: 200,
height: 200,
margin: 50,
background: 'yellow',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
fontSize: 36,
}}
>
{value}
</div>
);
}
export default Block;
The problem that I am having is that the two event handlers are closures so always print the value as it was when the component was mounted. I could rewrite the component as a class component and access the props via this but nothing else in the project uses class components. I could copy the value to a global variable but that would restrict me to a single instance.
What is the recommended way of accessing one or more props within a closure?
I should add that this was written to demonstrate the problem. In my app the value is a large object passed in and the div is a canvas with the data plotted onto it.
Advertisement
Answer
The easiest solution would be to use React synthetic events and remove the useEffect:
return <div onMouseEnter={mouseEnter} onMouseLeave={mouseLeave} ... />