npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ospm/eslint-plugin-react-unhookify

v1.0.2

Published

ESLint plugin to remove React hooks (useMemo, useCallback) and memo HOC for cleaner React code

Readme

eslint-plugin-react-unhookify

ESLint plugin to remove React hooks (useMemo, useCallback) and memo HOC for cleaner React code.

Note: With React Compiler 1.0 now stable, automatic memoization is handled at build time. This plugin is most useful for:

  • Projects using React Compiler
  • Codebases where manual memoization was over-used
  • Migrating legacy code before adopting React Compiler

Philosophy

This plugin follows the philosophy that:

  1. Memoization should be intentional: Only use memoization when you have measured performance problems
  2. Code simplicity matters: Unnecessary memoization adds complexity without benefits
  3. React is fast: Modern React is already optimized, and premature optimization can hurt more than help
  4. Developer experience: Cleaner code is easier to read, maintain, and debug

React Compiler 1.0 Context

React Compiler 1.0 (released October 2025) provides automatic memoization at build time, making manual useMemo, useCallback, and React.memo unnecessary in most cases.

Key Benefits of React Compiler

  • Automatic optimization: Analyzes component data flow and memoizes automatically
  • Better than manual: Can memoize in cases where hooks cannot be used (e.g., after early returns)
  • Production proven: Battle-tested at Meta with 12% faster loads and 2.5× faster interactions
  • Zero code changes: Works without requiring code rewrites

When to Use This Plugin vs React Compiler

| Scenario | Recommended Approach | |----------|----------------------| | New projects | Use React Compiler 1.0 | | Existing projects | Adopt React Compiler incrementally, use this plugin to clean up over-memoization | | Legacy codebases | Use this plugin to remove unnecessary memoization before compiler adoption | | Performance-critical code | Use React Compiler + manual memoization only as escape hatches |

React Compiler Recommendations

For new code: Rely on the compiler for memoization and use useMemo/useCallback only when you need precise control.

For existing code: Either leave existing memoization in place (removing it can change compilation output) or carefully test before removing.

Rules

remove-use-memo

Removes React.useMemo calls and inlines the computed value to simplify code by eliminating unnecessary memoization.

❌ Incorrect

const expensiveValue = React.useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedResult = useMemo(() => a + b, [a, b]);

✅ Correct

const expensiveValue = computeExpensiveValue(a, b);
const result = a + b;

Edge Cases (will NOT be flagged):

  • useMemo calls containing other React hooks (for safety)
  • Complex functions with multiple statements
  • Incorrect useMemo signatures

remove-use-callback

Removes React.useCallback calls and inlines the function to simplify code by eliminating unnecessary memoization.

❌ Incorrect

const handleClick = React.useCallback(() => {
  doSomething();
}, [doSomething]);

const handleChange = useCallback((event) => {
  console.log(event.target.value);
}, []);

✅ Correct

const handleClick = () => {
  doSomething();
};

const handleChange = (event) => {
  console.log(event.target.value);
};

remove-memo

Removes React.memo HOC calls and uses the component directly to simplify code by eliminating unnecessary memoization.

❌ Incorrect

const MyComponent = React.memo(() => {
  return <div>Hello</div>;
});

const MemoizedComponent = memo(({ name }) => {
  return <div>Hello {name}</div>;
});

✅ Correct

const MyComponent = () => {
  return <div>Hello</div>;
};

Installation

Option 1: React Compiler 1.0 (Recommended for new projects)

npm install --save-dev --save-exact babel-plugin-react-compiler@latest
npm install --save-dev eslint-plugin-react-hooks@latest

Option 2: This Plugin (For legacy cleanup or pre-compiler migration)

npm install @ospm/eslint-plugin-react-unhookify --save-dev

Option 3: Combined Approach

Use React Compiler for automatic optimization and this plugin to clean up legacy memoization:

npm install --save-dev --save-exact babel-plugin-react-compiler@latest
npm install --save-dev eslint-plugin-react-hooks@latest
npm install @ospm/eslint-plugin-react-unhookify --save-dev

Comparison: React Compiler vs Manual Memoization

| Feature | React Compiler 1.0 | Manual Memoization | This Plugin | |---------|-------------------|-------------------|------------| | Automatic optimization | ✅ Build-time analysis | ❌ Manual implementation | ❌ Manual cleanup | | Performance | 12% faster loads, 2.5× interactions | Varies by implementation | Removes unnecessary overhead | | Code simplicity | ✅ No manual hooks needed | ❌ Adds boilerplate | ✅ Cleaner code | | Control | Limited (escape hatches available) | ✅ Full control | ✅ Selective removal | | Learning curve | Low (install and enable) | High (need to understand patterns) | Low (auto-fix available) | | Best for | Most applications | Performance-critical cases | Legacy code cleanup |

Usage

Flat config (ESLint 9+)

import reactUnhookify from '@ospm/eslint-plugin-react-unhookify';

export default [
  {
    plugins: {
      'react-unhookify': reactUnhookify,
    },
    rules: {
      'react-unhookify/remove-use-memo': 'error',
      'react-unhookify/remove-use-callback': 'error',
      'react-unhookify/remove-memo': 'error',
    },
  },
];

Legacy config (ESLint 8)

module.exports = {
  plugins: ['react-unhookify'],
  rules: {
    'react-unhookify/remove-use-memo': 'error',
    'react-unhookify/remove-use-callback': 'error',
    'react-unhookify/remove-memo': 'error',
  },
};

Recommended Configuration

This plugin exports a recommended configuration that enables all rules.

Flat config

import reactUnhookify from '@ospm/eslint-plugin-react-unhookify';

export default [
  reactUnhookify.configs.recommended,
];

Legacy config

module.exports = {
  extends: ['plugin:react-unhookify/recommended'],
};

Options

All rules support the following options:

  • severity: Configure severity level for specific messages
  • performance: Configure performance tracking options
{
  rules: {
    'react-unhookify/remove-use-memo': ['error', {
      severity: {
        removeUseMemo: 'warn' // 'error' | 'warn' | 'off'
      },
      performance: {
        maxNodes: 1000,
        maxTime: 100,
        enableMetrics: false,
        logMetrics: false
      }
    }]
  }
}

Auto-fixing

All rules support auto-fixing. The plugin will:

  1. For useMemo: Extract the computed value and inline it
  2. For useCallback: Remove the wrapper and inline the function
  3. For memo: Remove the HOC wrapper and use the component directly

Example Auto-fix

Before:

const value = React.useMemo(() => calculateSomething(a, b), [a, b]);
const fn = useCallback(() => doSomething(), []);
const Component = React.memo(() => <div>Hello</div>);

After auto-fix:

const value = calculateSomething(a, b);
const fn = () => doSomething();
const Component = () => <div>Hello</div>;

Safety Considerations

The plugin includes safety checks to avoid breaking changes:

  • Hook Detection: Won't remove useMemo if the computed value contains other React hooks
  • Complex Functions: Won't inline functions with multiple statements
  • Signature Validation: Only processes valid hook/memo signatures
  • Type Safety: Maintains TypeScript types and interfaces

When NOT to Use This Plugin

Do not use this plugin if:

  • You're using React Compiler 1.0: The compiler handles memoization automatically
  • You have measured performance issues: Keep memoization that solves real performance problems
  • You're working on performance-critical components: Manual memoization may still be necessary
  • Your team has established memoization patterns: Consider team conventions and code review practices
  • You're building a library: Memoization might be part of your public API
  • You need precise control: Use manual memoization as escape hatches with React Compiler

React Compiler Migration Strategy

If you're planning to adopt React Compiler 1.0:

Phase 1: Preparation

  1. Audit current memoization: Use this plugin to identify unnecessary useMemo, useCallback, and React.memo
  2. Clean up over-memoization: Remove memoization that doesn't provide value
  3. Test thoroughly: Ensure components work correctly after changes

Phase 2: Compiler Adoption

  1. Install React Compiler: npm install --save-dev --save-exact babel-plugin-react-compiler@latest
  2. Enable gradually: Start with non-critical components
  3. Monitor performance: Measure improvements and regressions

Phase 3: Optimization

  1. Use manual memoization sparingly: Only as escape hatches for precise control
  2. Leverage compiler diagnostics: Use eslint-plugin-react-hooks@latest for compiler-powered linting
  3. Profile and measure: Verify the compiler is providing expected benefits

Real-world Results

  • Meta Quest Store: 12% faster initial loads, 2.5× faster interactions
  • Sanity Studio: 20-30% reduction in render time and latency
  • Wakelet: 10% LCP improvement, 15% INP improvement

Traditional Migration Strategy (Without React Compiler)

If you're not adopting React Compiler:

  1. Start with warnings: Use 'warn' severity instead of 'error' initially
  2. Review changes: Manually review auto-fixes before applying
  3. Test thoroughly: Ensure components still work after memoization removal
  4. Measure performance: Verify that removal doesn't impact performance

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests.

License

MIT