nextjs - 💡(How to fix) Fix function are not memorized correctly when using react-compiler [3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#86039Fetched 2026-04-08 02:12:51
View on GitHub
Comments
3
Participants
3
Timeline
9
Reactions
1
Author
Timeline (top)
commented ×3labeled ×2closed ×1issue_type_added ×1

Code Example

function Test1() {
    const [expire, setExpire] = useState(5)
    useEffect(() => {
        const timer = setInterval(() => {
            setExpire((prev) => prev - 1)
        }, 1000)
        if (expire === 0) {
            clearInterval(timer)
        }
        return () => clearInterval(timer)
    }, [expire])
    const onClick = () => {
        console.log('isExpired', isExpired)
    }
    const isExpired = expire === 0
    return <div onClick={onClick} className="text-red-500">{expire}</div>
}

---

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
  Available memory (MB): 65536
  Available CPU cores: 10
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: 4.2.2
  pnpm: 10.15.1
Relevant Packages:
  next: 16.0.1 // Latest available version is detected (16.0.1).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/promer94/incorrect-memo-fn-nextjs

To Reproduce

  1. build the application with next build
  2. start the application with next start
  3. click the numbers to see the console log

Current vs. Expected behavior

function Test1() {
    const [expire, setExpire] = useState(5)
    useEffect(() => {
        const timer = setInterval(() => {
            setExpire((prev) => prev - 1)
        }, 1000)
        if (expire === 0) {
            clearInterval(timer)
        }
        return () => clearInterval(timer)
    }, [expire])
    const onClick = () => {
        console.log('isExpired', isExpired)
    }
    const isExpired = expire === 0
    return <div onClick={onClick} className="text-red-500">{expire}</div>
}

The onclick function should be able to access the latest value of isExpired

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
  Available memory (MB): 65536
  Available CPU cores: 10
Binaries:
  Node: 22.18.0
  npm: 10.9.3
  Yarn: 4.2.2
  pnpm: 10.15.1
Relevant Packages:
  next: 16.0.1 // Latest available version is detected (16.0.1).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

React

Which stage(s) are affected? (Select all that apply)

next start (local), next build (local)

Additional context

No response

extent analysis

TL;DR

The issue can be resolved by using the useCallback hook to memoize the isExpired value and update it when the expire state changes.

Guidance

  • The isExpired variable is not being updated because it's not a state variable and is only calculated once when the component renders.
  • To fix this, you can use the useMemo hook to recalculate isExpired whenever expire changes.
  • You can also use the expire state directly in the onClick function to log the correct value.
  • Consider using useEffect with the correct dependency to update the isExpired value.

Example

function Test1() {
    const [expire, setExpire] = useState(5)
    const isExpired = useMemo(() => expire === 0, [expire])
    useEffect(() => {
        const timer = setInterval(() => {
            setExpire((prev) => prev - 1)
        }, 1000)
        return () => clearInterval(timer)
    }, [])
    const onClick = () => {
        console.log('isExpired', expire === 0)
    }
    return <div onClick={onClick} className="text-red-500">{expire}</div>
}

Notes

This solution assumes that the isExpired value should be updated whenever the expire state changes. If this is not the case, you may need to adjust the dependency array of the useMemo hook.

Recommendation

Apply workaround: The provided example code snippet demonstrates a possible workaround for the issue, using useMemo to recalculate the isExpired value whenever expire changes.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - 💡(How to fix) Fix function are not memorized correctly when using react-compiler [3 comments, 3 participants]