DEV Community

Discussion on: React hooks & the closure hell 2

Collapse
 
shiatsumat profile image
Yusuke Matsushita • Edited

Your post enlightened me a lot.
I wrote a simpler function based on your idea. On TypeScript, this style may be preferable since different handlers can have different types.
codesandbox.io/s/react-usehandler-...

/* based on https://dev.to/anpos231/react-hooks-the-closure-hell-2-58g9 */

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

import "./styles.css";

const useHandler = preHandler => {
  let ref = useRef({ altHandler: null, handler: null });
  if (!ref.current.handler) {
    ref.current.handler = (...args) => ref.current.altHandler(...args);
  }
  ref.current.altHandler = preHandler;
  return ref.current.handler;
};

let times = 0;
const ExpensiveComponent = memo(({ onClick }) => (
  <p onClick={onClick}>re-render: {times++}</p>
));

const App = () => {
  const [value, setValue] = useState(1);
  const handleClick = useHandler(_ => {
    setValue(value + 1);
  });
  /* instead of
  const handleClick = _ => {
    setValue(value + 1);
  }; 
  */
  return (
    <div className="app">
      <ExpensiveComponent onClick={handleClick} />
      <button onClick={handleClick}>increment value</button>
      <p>{value}</p>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Collapse
 
shiatsumat profile image
Yusuke Matsushita • Edited

In this particular situation, if we pass an update function to setValue instead, it suffices to simply use useCallback with an empty dependency list. (Notably, useCallback((...) => ..., []) is equivalent to useRef((...) => ...).current.)

/* based on https://dev.to/anpos231/react-hooks-the-closure-hell-2-58g9 */

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

import "./styles.css";

let times = 0;
const ExpensiveComponent = memo(({ onClick }) => (
  <p onClick={onClick}>re-render: {times++}</p>
));

const App = () => {
  const [value, setValue] = useState(1);
  const handleClick = useCallback(_ => {
    setValue(value => value + 1);
  }, []);
  return (
    <div className="app">
      <ExpensiveComponent onClick={handleClick} />
      <button onClick={handleClick}>increment value</button>
      <p>{value}</p>
    </div>
  );
};

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

So are you saying that we can function to setValue? And it will call it with the current state? Just like the old this.setState()?

How could I miss it!