React useMemo

useMemo hook helps you to cache variables between re-renders.

import { useEffect, useState, useMemo } from "react";

function UserPage() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [isActive, setIsActive] = useState(false);

  const person = useMemo(() => {
    return { firstName, lastName };
  }, [firstName, lastName]);

  useEffect(() => {
    console.log("person:", person);
  }, [person]);

  const handleFirstNameChange = (e) => {
    setFirstName(e.target.value);
  };

  const handleLastNameChange = (e) => {
    setLastName(e.target.value);
  };

  const handleActiveChange = (e) => {
    setIsActive(e.target.checked);
  };

  return (
    <form>
      <input
        type="text"
        value={firstName}
        onChange={handleFirstNameChange}
      />
      <input
        type="text"
        value={lastName}
        onChange={handleLastNameChange}
      />
      <label>
        <input
          type="checkbox"
          checked={isActive}
          onChange={handleActiveChange}
        />
        Active
      </label>

      <p>Person: {JSON.stringify(person)}</p>
    </form>
  );
}

export default UserPage;

The 'person' object makes the dependencies of useEffect Hook change on every render. So console.log will run on every checkbox click. To fix this, wrap the initialization of 'person' in its own useMemo() Hook.
The reason of it is because of referential equality and redefining new person object after every re-render.
Also check eslintreact-hooks/exhaustive-deps.

import { useEffect, useState } from "react";

function UserPage() {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [isActive, setIsActive] = useState(false);

  const person = { firstName, lastName };

  useEffect(() => {
    console.log("person:", person);
  }, [person]);

  const handleFirstNameChange = (e) => {
    setFirstName(e.target.value);
  };

  const handleLastNameChange = (e) => {
    setLastName(e.target.value);
  };

  const handleActiveChange = (e) => {
    setIsActive(e.target.checked);
  };

  return (
    <form>
      <input
        type="text"
        value={firstName}
        onChange={handleFirstNameChange}
      />
      <input
        type="text"
        value={lastName}
        onChange={handleLastNameChange}
      />
      <label>
        <input
          type="checkbox"
          checked={isActive}
          onChange={handleActiveChange}
        />
        Active
      </label>

      <p>Person: {JSON.stringify(person)}</p>
    </form>
  );
}
export default UserPage;

Leave a Comment