Skip to content
Advertisement

Access props from a closure function within a functional component

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} ... />
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement