一个关于 react 函数组件重新渲染的问题

2021-04-19 21:11:43 +08:00
 wiluxy

点击按钮后,触发 setCount(0+1), 此时 count 改变,改变后 count 为 1,函数重新渲染 输出"render" 然后再次点击按钮,触发 count+1,但是外面包了一层 useCallback,函数里面的 count 应该是第一次渲染时的 count,也就是 setCount(0+1),第二次点击 connt 是没有变的,但是函数还是重新渲染了,输出了"render",这是为什么呢?

代码如下

import React, { useCallback,  useState } from "react";

const App = () => {

  console.log("render");
  
  const [count, setCount] = useState(0);

  const Add = useCallback(() => {
    setCount(count + 1);
  }, []);

  return (
    <div>
      {count}
      <button onClick={Add}>add count</button>
    </div>
  );
};

export default App;
3193 次点击
所在节点    React
25 条回复
liuqiongyu889
2021-04-20 13:51:06 +08:00
@wiluxy 这个我有点不解了,因为你这种做法有点违背 hook 的最佳实践用法,可能得挖挖源码看下喽,React Hook 最佳实践: https://markdowner.net/article/170279075167232000,外国人写的,翻译文。
SystemLight
2021-04-20 17:19:04 +08:00
我理解的是把函数式组件看成类组件的 render 方法,里面的 hook 相比类组件的其它定义方法,一旦组件内状态改变就会调用 render 方法去重新渲染生成新的 VDOM,而且是从根节点往下传递的
wiluxy
2021-04-20 17:44:57 +08:00
@SystemLight 已知的是 useState 的修改函数,传入的值新旧比较是用 Object.is 来比较的,如果一样的就不会进行更新

~~~js
const [user,setUser] = useState({
name:"tim"
})

setUser(u=>{
u.name = "jojo"
return u
});
~~~
向上面这样调用 setState 函数是不会触发更新的,但是我的疑问是 帖子内容的代码第一次执行 setCount(1)的时候函数重新渲染了,但是第二次 setCount(1),count 的值没有变化,函数还是重新渲染了,第三次第四五次之后再点又没有出现组件函数重新渲染的行为
7anshuai
2021-04-20 20:35:59 +08:00
SystemLight
2021-04-21 10:32:14 +08:00
粗略看了下 react-dom 源码,其中有一部分是这样子的

```
function dispatchAction(fiber, queue, action) {
...

if (fiber.lanes === NoLanes && (alternate === null || alternate.lanes === NoLanes)) {
...
if (objectIs(eagerState, currentState)) {
// Fast path. We can bail out without scheduling React to re-render.
// It's still possible that we'll need to rebase this update later,
// if the component re-renders for a different reason and by that
// time the reducer has changed.
return;
}
}
...
}
```

状态改变后,第二次设置的值的时候,fiber.lanes 的标记会从 NoLanes 变为存在 SyncLane,如果没有同步的话是根本不会进行 objectIs 进行状态比较的,我的理解是 fiber 需要一回做同步,因为无法准确确定出某些事情,所以只能在下回合更新时进行执行判断

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/771755

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX