0
votes

Newbie to react here, what is the right way to manage state from synthetic events using hooks and update the state from event handlers, i have gone through the official react documentation and could not find the specific information.

This is what i have tried so far.

Step 1: Declare the hook variable using which we will update state

const [state, setState] = React.useState(0);

Step 2: Declare the function to handle synthetic event & update the state

const handleCopy = (e) => {
   setState(state+1);
   e.preventDefault();
};

Step 3: Add event listener and pass event to the function

document.addEventListener('copy', (e) => handleCopy(e));

Step 4: Pass the state to the component

<Component value={state}/>

There are few problem i face here though

  1. The state update is not reflecting in the component. But it does seem to be updating the state since the console.log seems to reflect the state correctly.
  2. There are too many event-listeners getting registered over time.

To prevent too many event-listeners i wrapped the addEventListener with a condition to register only once

const [syntheticEventRegistered, setSyntheticEventRegistered] = React.useState(false);

if(!syntheticEventRegistered)
{
    document.addEventListener('copy', (e) => handleCopy(e));
    setSyntheticEventRegistered(true);
}

This did resolve too many event listeners, but the handleCopy function now reflects only default state. i.e state = 0 instead of latest state nor does this update Component value.

1

1 Answers

1
votes

Registering an event listener is recommended in the componentDidMount lifecycle. You can use the useEffect hook in a functional component instead. With useEffect you can subscribe and unsuscribe to en event (in a return function). This way you can prevent multiple registration. I created an example.

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

import "./styles.css";
const MyFunctionalComponent = () => {
  let [state, setState] = useState(0);

  useEffect(() => {
    const handleCopy = e => {
      setState(state + 1);
      e.preventDefault();
    };

    document.addEventListener("copy", handleCopy);
    // Specify how to clean up after this effect:
    return () => {
      document.removeEventListener("copy", handleCopy);
    };
  }, [state]);

  return <div>{state}</div>;
};

function App() {
  return (
    <div className="App">
      <MyFunctionalComponent />
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

You can check out here: https://codesandbox.io/s/little-rgb-dfre7

It works for me. If you select something from the right side and press ctrl+c the counter increases.