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

相关推荐
烬头882119 分钟前
React Native鸿蒙跨平台采用了函数式组件的形式,通过 props 接收分类数据,使用 TouchableOpacity实现了点击交互效果
javascript·react native·react.js·ecmascript·交互·harmonyos
Amumu1213819 分钟前
Vuex介绍
前端·javascript·vue.js
2601_9498095931 分钟前
flutter_for_openharmony家庭相册app实战+相册详情实现
javascript·flutter·ajax
qq_1777673736 分钟前
React Native鸿蒙跨平台通过Animated.Value.interpolate实现滚动距离到动画属性的映射
javascript·react native·react.js·harmonyos
2601_949833391 小时前
flutter_for_openharmony口腔护理app实战+饮食记录实现
android·javascript·flutter
2601_949480061 小时前
【无标题】
开发语言·前端·javascript
css趣多多1 小时前
Vue过滤器
前端·javascript·vue.js
●VON1 小时前
React Native for OpenHarmony:项目目录结构与跨平台构建流程详解
javascript·学习·react native·react.js·架构·跨平台·von
爱吃大芒果2 小时前
Flutter for OpenHarmony 实战:mango_shop 路由系统的配置与页面跳转逻辑
开发语言·javascript·flutter
qq_177767372 小时前
React Native鸿蒙跨平台实现消息列表用于存储所有消息数据,筛选状态用于控制消息筛选结果
javascript·react native·react.js·ecmascript·harmonyos