React组件更新:探究两个典型案例

案例一

有时候我们可能会看到这样的react 代码:

javascript 复制代码
const Child1 = () => {
  return <div>Child1</div>;
};

function App() {
  const Child2 = () => {
    return <div>Child2</div>;
  };
  return (
    <div>
      <Child1 />
      <Child2 />
    </div>
  );
}

在过去,我傻傻地以为像 Child2 这样把组件定义在另一个组件内部和 Child1 没啥区别。但事实证明,这是大错特错!原来我们应该一直像 Child1 那样定义组件,因为 Child2 会招来巨大的性能麻烦。

App 组件更新时,会重新执行一次 App 函数。由于 App 函数内部每次都要新建一个 Child2,经过 Babel 编译后,它就成了 {type: Child2,...}。React 在组件更新时,会比较新旧节点的 type 是否相等,来决定是否复用老元素。然而,由于 type → Child2 永远是新函数,就算长得和老的一模一样,React 也会狠心地删除旧的 Child2,然后又创建一个一模一样的新 Child2

所以我们应该一直使用Child1 的方式来定义组件。

案例二

下面我们再看一段代码

tsx 复制代码
function App() {
  return (
    <Child>
      <GrandChild />
    </Child>
  );
}

const GrandChild = () => {
  console.log('render-grand-child');
  return <div>GrandChild</div>;
};

const GrandChild1 = () => {
  console.log('render-grand-child1');
  return <div>GrandChild1</div>;
};

const Child = (props: any) => {
  const [count, setCount] = useState(0);
  const onClick = () => {
    setCount(count + 1);
  };
  return (
    <div onClick={onClick}>
      <h2>{count}</h2>
      {/* 通过children属性传入 */}
      {props.children}
      {/* 直接写到Child组件中 */}
      <GrandChild1 />
    </div>
  );
};

Child 组件更新时,GrandChild1 会重新执行,而 GrandChild 就好像没事发生一样。

我们看一下在babel编译以后的代码:

为了方便理解,我们将代码进行简化:

tsx 复制代码
const jsx = (type,props) => {
    return {
            type,
            props
    }
}

const GrandChildElement = jsx(GrandChild,{})

// 省略其它无关元素
const Child = () => {
    return (
            {GrandChild1Element}
            jsx(GrandChild1,{})
    )
}

可以看到,每次 Child 重新执行时,都要重新创建一个新的 props 用于 GrandChild1,而 GrandChild 则复用了老的已创建好的 props。React 在组件更新时,会比对新旧节点的 props 是否相同,以决定是否重新执行函数组件。所以 GrandChild1 被重新执行,而 GrandChild 由于与老节点使用相同的 props,因此不会重新执行。

这俩个问题曾经困扰了我很久,最近在阅读React源码时,又再次重新理解了这些代码的执行细节。希望这些内容也能对你理解React代码有帮助

这俩问题曾困扰了我很久,直到最近我在研究 React 源码时,重新思考这俩个问题,感觉豁然开朗!希望这些内容也能给你在学习中带来一些启发。

相关推荐
胡志辉29 分钟前
深入浅出 call、apply、bind
前端·javascript·后端
十九画生3 小时前
parentID ``` JavaScript 是区分大小写的,所以这两个不是同一个字段。 第二,`parent` 没有声明。 应该先写: `
javascript
怕浪猫4 小时前
Electron 开发实战(十六):总结与展望|生态现状、框架对比、行业趋势与学习指南
前端·javascript·electron
ZengLiangYi5 小时前
批量导入 1000 条对话的性能优化实战
javascript·后端·架构
竹林8185 小时前
用 wagmi v2 + viem 监听合约事件时踩的坑,我花了两天才把"遗漏事件"修好
javascript
YFF菲菲兔5 小时前
finishConcurrentRender 源码解析
react.js
小花酱酱5 小时前
QQ群里只有你一个人?邪门歪道破局之路——AstrBot
javascript
bonechips5 小时前
JS 数组指南:从内存原理到二维矩阵
前端·javascript
YFF菲菲兔5 小时前
reconcileChildren 源码解析
react.js
mONESY5 小时前
前端零基础精讲:Canvas3D、CSS3D、文档流、定位全方位复盘
javascript