lxsmnsyc / forgetti

Solve your hook spaghetti (with more spaghetti). Inspired by React Forget.
https://forgetti.vercel.app/
MIT License
352 stars 7 forks source link

Incorrect transformation of useCallback #7

Closed SukkaW closed 1 year ago

SukkaW commented 1 year ago

Input

import { useCallback, useState } from 'react';

export default function Example() {
  const [count, setCount] = useState(0);
  const handleIncrement = useCallback(() => setCount(c => c + 1), []);

  return (
    <button onClick={handleIncrement}>{count}</button>
  );
}

Output

import { jsx as _jsx } from "react/jsx-runtime";
import { useMemo as _useMemo } from "react";
import { $$cache as _$$cache } from "forgetti/runtime";
import { $$equals as _$$equals } from "forgetti/runtime";
import { useCallback } from 'react';
import { useState } from 'react';
export default function Example() {
    var _c, _ref;
    let _c1 = _$$cache(_useMemo, 5);
    const [count, setCount] = useState(0);
    let _v = (_c = _c1)[_ref = 0] || (_c[_ref] = []), _eq = _$$equals(_c1[1], ()=>setCount((c)=>c + 1)), _v2 = _eq ? _c1[1] : _c1[1] = ()=>setCount((c)=>c + 1);
    const handleIncrement = _v2;
    let _eq2 = _$$equals(_c1[2], handleIncrement), _v3 = _eq2 ? _c1[2] : _c1[2] = handleIncrement, _eq3 = _$$equals(_c1[3], count), _v4 = _eq3 ? _c1[3] : _c1[3] = count, _eq4 = _eq2 && _eq3, _v5 = _eq4 ? _c1[4] : _c1[4] = /*#__PURE__*/ _jsx("button", {
        onClick: _v3,
        children: _v4
    });
    return _v5;
}

Notice the useCallback transformation:

let _eq = _$$equals(_c1[1], ()=>setCount((c)=>c + 1));
let _v2 = _eq ? _c1[1] : _c1[1] = ()=>setCount((c)=>c + 1);
const handleIncrement = _v2;

Whenever React re-renders, ()=>setCount((c)=>c + 1) is always re-created, thus it will always have a different reference with _c1[1], and result in _eq will always be false.

lxsmnsyc commented 1 year ago

Seems like a regression, thanks for spotting this