Try @eslint-react/kit@beta
logoESLint React

use-memo

Validates that 'useMemo' is called with a callback that returns a value.

Full Name in eslint-plugin-react-x

react-x/use-memo

Full Name in @eslint-react/eslint-plugin

@eslint-react/use-memo

Presets

x recommended recommended-typescript recommended-type-checked strict strict-typescript strict-type-checked

Rule Details

This rule ensures that useMemo() callbacks follow React's requirements. It checks for several common mistakes:

  1. Callbacks should not accept parameters (useMemo callbacks are called with no arguments)
  2. Callbacks should not be async or generator functions (must return a value synchronously)
  3. Callbacks should not reassign variables declared outside the callback (must be pure)
  4. Callbacks should return a value (useMemo is for computing values, not side effects)
  5. The result of useMemo should be used (not discarded)

Common Violations

Invalid

Callback with parameters

import { useMemo } from "react";

function Component({ a, b }) {
  const x = useMemo((c) => a + c, [a]);
  //                 ^^ Callbacks with parameters are not supported
  return <div>{x}</div>;
}

Async or generator callback

import { useMemo } from "react";

function Component({ a }) {
  const x = useMemo(async () => {
    //             ^^^^^^^^^^^^^ Async and generator functions are not supported
    return await fetchData(a);
  }, [a]);
  return <div>{x}</div>;
}

Reassigning outer variables

import { useMemo } from "react";

function Component() {
  let x;
  const y = useMemo(() => {
    x = [];
    // ^^^ Cannot reassign variable
    return true;
  }, []);
  return <div>{x}{y}</div>;
}

No return value

import { useMemo } from "react";

function Component({ data }) {
  const processed = useMemo(() => {
    data.forEach((item) => console.log(item));
    // Missing return! Callback must return a value.
  }, [data]);
  return <div>{processed}</div>; // Always undefined
}

Result not assigned

import { useMemo } from "react";

function Component({ user }) {
  useMemo(() => {
    // ^^^^^^ useMemo() result is unused
    return heavyComputation(user);
  }, [user]);
  return <div />;
}

Valid

Returns a computed value

import { useMemo } from "react";

function Component({ data }) {
  const processed = useMemo(() => {
    return data.map((item) => item * 2);
  }, [data]);
  return <div>{processed}</div>;
}

Arrow function with concise body

import { useMemo } from "react";

function Component({ items }) {
  const sorted = useMemo(() => [...items].sort(), [items]);
  return <div>{sorted.join(", ")}</div>;
}

Reads outer variables without reassigning

import { useMemo } from "react";

function Component({ a, b }) {
  const sum = useMemo(() => a + b, [a, b]);
  return <div>{sum}</div>;
}

Resources

Further Reading


See Also

  • react-x/use-state
    Enforces correct usage of useState, including destructuring, symmetric naming of the value and setter, and wrapping expensive initializers in a lazy initializer function.

On this page