Skip to content

Reverse React Compiler™ Has Fix

Description

React Compiler is a build-time only tool that automatically optimizes your React app, working with plain JavaScript and understanding the Rules of React without requiring a rewrite. It optimizes apps by automatically memoizing code, similar to useMemo, useCallback, and React.memo, reducing unnecessary recomputation due to incorrect or forgotten memoization.

Reverse React Compiler™ is a parody tweet that works in the opposite direction. It takes React code and removes memoization, guaranteed to make your code slower. (not necessarily)

It is originally written in Babel and this is an ast-grep version of it.

The Original Babel Implementation

For comparison purposes only. Note the original code does not correctly rewrite useMemo.

js
const ReverseReactCompiler = ({ types: t }) => ({
  visitor: {
    CallExpression(path) {
      const callee = path.node.callee;
      if (
        t.isIdentifier(callee, { name: "useMemo" }) ||
        t.isIdentifier(callee, { name: "useCallback" }) ||
        t.isIdentifier(callee, { name: "memo" })
      ) {
        path.replaceWith(args[0]);
      }
    },
  },
});

YAML

yaml
id: rewrite-cache
language: tsx
rule:
  any:
  - pattern: useCallback($FN, $$$)
  - pattern: memo($FN, $$$)
fix: $FN
---
id: rewrite-use-memo
language: tsx
rule: { pattern: 'useMemo($FN, $$$)' }
fix: ($FN)()   # need IIFE to wrap memo function

Example

tsx
const Component = () => {
  const [count, setCount] = useState(0)
  const increment = useCallback(() => {
    setCount((prevCount) => prevCount + 1)
  }, [])
  const expensiveCalculation = useMemo(() => {
    // mock Expensive calculation
    return count * 2
  }, [count])

  return (
    <>
      <p>Expensive Result: {expensiveCalculation}</p>
      <button onClick={increment}>{count}</button>
    </>
  )
}

Diff

tsx
const Component = () => {
  const [count, setCount] = useState(0)
  const increment = useCallback(() => {     
    setCount((prevCount) => prevCount + 1)  
  }, [])                                 
  const increment = () => {         
    setCount((prevCount) => prevCount + 1) 
  } 
  const expensiveCalculation = useMemo(() => { 
    // mock Expensive calculation             //
    return count * 2
  }, [count])                             
  const expensiveCalculation = (() => { 
    // mock Expensive calculation      //
    return count * 2
  })()                            
  return (
    <>
      <p>Expensive Result: {expensiveCalculation}</p>
      <button onClick={increment}>{count}</button>
    </>
  )
}

Contributed by

Inspired by Aiden Bai

Made with ❤️ with Rust