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 源码时,重新思考这俩个问题,感觉豁然开朗!希望这些内容也能给你在学习中带来一些启发。

相关推荐
三十而立洋10 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁11 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄11 小时前
JavaScript 隐式全局变量解析
javascript
沙蒿同学13 小时前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端
paopaokaka_luck14 小时前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
Hilaku15 小时前
为什么死磕 1px 的团队,用户体验反而更差?
前端·javascript·程序员
陈拉斯16 小时前
给公司年会写了个大屏抽奖系统:动画在前端跑,凭什么说结果没被改?
javascript
yzy8516 小时前
Vue中下载或打开文件的JavaScript方法
前端·javascript·vue
用户2986985301417 小时前
在 React 中用 JavaScript 将 Word 转换为文本
前端·javascript·react.js
李少兄18 小时前
深入解析 JavaScript 中的 `document` 对象
javascript