Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

精读《React useEvent RFC》 #415

Closed
ascoders opened this issue May 14, 2022 · 10 comments
Closed

精读《React useEvent RFC》 #415

ascoders opened this issue May 14, 2022 · 10 comments

Comments

@ascoders
Copy link
Owner

ascoders commented May 14, 2022

useEvent 这个提案解决了 useCallback 的痛,本周我们结合 RFC 原文与解读文章 What the useEvent React hook is (and isn't) 一起了解下这个提案。


精读《React useEvent RFC》

@wellssu0
Copy link

注意两段注释,第一个是 useLayoutEffect 部分实际上要比 layoutEffect 执行时机更提前,,这里的layoutEffect是不是写错了?

@crazylxr
Copy link

这就是 hooks 带来的副作用,一直在打补丁。

@eczn
Copy link

eczn commented May 17, 2022

参考一下 vue useRef 的设计,也许可以这样?引入太多机制不太好吧

export function useRef<T>(value: T) {
  const ref = React.useRef(value);

  const [$1, renderSetter] = React.useState(value);

  const setState = React.useCallback((newValue: T) => {
    ref.current = value;
    renderSetter(newValue);
  }, []);

  return [ref, setState] as const;
}

export function App() {
  const [countRef, setCount] = useRef(0);

  const onXXXCallback = React.useCallback(() => {
    countRef.current; // 始终是最新的 state, onXXXCallback 也是稳定的
  }, []);

  return (
    <div onClick={() => setCount(countRef.current + 1)}>
      { countRef.current }
    </div>
  );
}

也许有个更快的方式, useState 再多返回一个 getter

const [count, setCount, getCount] = React.useState(0);

@ascoders
Copy link
Owner Author

@eczn 不错的想法。有个小问题,这样对于 props 传入的值都要包裹一层 useRef,用起来还是不如 useEvent 方便。

@ystrdy
Copy link

ystrdy commented May 21, 2022

注意两段注释,第一个是 useLayoutEffect 部分实际上要比 layoutEffect 执行时机更提前,,这里的layoutEffect是不是写错了?

我觉得这里的意思应该是说,useEvent示例里面的useLayoutEffect的执行时机,应该在其他的layout effects之前

@GitHdu
Copy link

GitHdu commented Jun 14, 2022

// (!) Approximate behavior
function useEvent(handler) {
  const handlerRef = useRef(null);

  // 新手求问,这里为啥要包裹一层,不能直接赋值吗
  useLayoutEffect(() => {
    handlerRef.current = handler;
  });

  return useCallback((...args) => {
    // In a real implementation, this would throw if called during render
    const fn = handlerRef.current;
    return fn(...args);
  }, []);
}

@a243065157
Copy link

a243065157 commented Jun 14, 2022 via email

@AndyBoat
Copy link

@GitHdu 应该是为了模仿原生 useEvent 的行为
即, 原生的 useEvent 定义的函数, 不允许在 render 阶段执行, 所以我推测这里是在模拟使得第一次的 render 调用方法时必然会报错,; 当然到了后续的 render 就阻止不了, 所以有了 useCallback 里面的注释;
另一方面, 这里也是用于描述useEvent注册的函数准备好的时机, 是在 render 阶段后, 和 各个layoutEffect/effect 执行之前.
当然这个精确的时机, 根据 RFC 的描述, 好像还没想好

@GitHdu
Copy link

GitHdu commented Jun 23, 2022

@AndyBoat 抛开模仿原生 useEvent 的行为不说,
为啥要包一层呢

@projectcss
Copy link

“值并不是真正意义上的实时”这个论点其实从react设计上看它是做不到实时的,就算我们不用useCallback、useEvent这些hook,定义成纯函数也是做不到的(除了ref),因为都存在闭包问题,只有在组件再次渲染之后才回去更新值

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants