当前位置: 首页 > news >正文

苏州网站建设公司找哪家最好的网页设计公司

苏州网站建设公司找哪家,最好的网页设计公司,网站快速推广,wordpress 虎嗅网传入props.children后, 为什么会导致组件的重新渲染? 问题描述 在 react 中, 我想要对组件的渲染进行优化, 遇到了一个非常意思的问题, 当我向一个组件中传入了 props.children 之后, 每次父组件重新渲染都会导致这个组件的重新渲染; 它看起来的表现就像是被memo包…

传入props.children后, 为什么会导致组件的重新渲染?

问题描述

在 react 中, 我想要对组件的渲染进行优化, 遇到了一个非常意思的问题, 当我向一个组件中传入了 props.children 之后, 每次父组件重新渲染都会导致这个组件的重新渲染; 它看起来的表现就像是被memo包裹的组件, props和自身状态未发生变化, 组件却重新渲染了; 下面我写了一个demo, 一起来看看这个问题吧:

父组件App中引入了一个Home组件:

import Home from "./pages/Home";
import { useState } from "react";function App() {const [count, setCount] = useState(0);console.log("App is render");return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>Increment</button><Home></Home></div>);
}

使用 memo 包裹 Home 子组件, 同时 Home 组件可以接收一个 props.children 展示传入到 Home 中的组件, 如下:

import React, { memo } from "react";const Home = memo((props) => {console.log("Home is render");return (<div>Home{props.children}</div>);
});export default Home;

目前在 App 组件中, 没有向 Home 组件中传入 props.children, 此时第一次加载时 App 组件和 Home 组件都会重新渲染, 当我们点击 Increment 按钮让 count 的值变化时, App 组件重新渲染, 由于 Home 组件被 memo 包裹, 当 Home 组件的 props 和自身状态未发生变化时, 组件不进行重新渲染, 目前也正是我们所期望的这样, 没有问题。

但是, 当我们在 App 组件中向 Home 组件传入 props.children 时, 就会出现问题(此问题不仅限于我下面例子中传入了一个 About 组件, 传入任何元素都会出现这个问题, 即使我们传入一个简单的 div 元素):

import { useState } from "react";
import Home from "./pages/Home";
import About from "./pages/About";function App() {const [count, setCount] = useState(0);console.log("App is render");return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>Increment</button><Home><About /></Home></div>);
}

About 组件同样使用 memo 包裹, 代码如下:

import React, { memo } from "react";const About = memo(() => {console.log("About is render");return <div>About</div>;
});export default About;

此时如果我们修改 count 的值, 会导致 App 组件重新渲染, 但是也会导致 Home 组件重新渲染。这就有些令人疑惑, 我们来分析一下:

首先我们知道, 在未经过任何优化的情况下, 父组件重新渲染一定会导致子组件的重新渲染, 那么也就会创建一个新的组件实例; 而如果使用 memo 对组件进行包裹, 那么在组件的 props 和自身状态没有发生变化的情况下, 父组件重新渲染子组件不会重新渲染, 是不是意味着不会创建一个新的组件实例呢? (这里进入了思维误区)

上面代码中, 我们向 Home 组件中传递了一个 About 组件, 目前 Home 组件中的表现就相当于 props.children = <About/>, 由于 Home 组件被 memo 包裹还重新渲染了, 那大几率是 props 发生了变化。纠结之处就在于, 此时 props 中又只有 children 一个属性, 值为 About 组件, About 组件同样被 memo 包裹, 且没有依赖任何 props 和状态, 如果 About 组件返回的结果应该是相同的, 就不应该导致 Home 组件的 props 发生变化才对。

这就是我所遇到的问题, 为什么 props.children 会影响组件的渲染呢?

问题分析

我依然怀疑是由 Home 组件的 props 发生了变化, 唯一可能变化的就是 About 组件, 为了验证我的想法, 于是我在Home 组件中定义了一个 aboutRef 变量, 使用 useRef 包裹 About 组件, 如下所示:

import Home from "./pages/Home";
import { useState } from "react";function App() {const [count, setCount] = useState(0);// 使用useRef包裹const aboutRef = useRef(<About/>);console.log("App is render");return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>Increment</button><Home>{aboutRef.current}</Home></div>);
}

此时我发现, 首次渲染时 App、Home、About 都会渲染, 而当 count 发生变化时, 只有 App 组件重新渲染了, 这也就达到了我最初期望的效果。但是为什么包裹了 useRef 才可以做到这个效果呢? 到这里已经可以确定的是 Home 组件的 props.children 一定是发生了变化的, 那么我们来探讨一下 About 组件为什么会变化。

变化的原因是因为组件每次重新渲染时都会创建 React 元素, 例如<About /> = jsx(About), 并且在调用时会返回一个新对象, 当然不只是 About 会这样创建, 其他组件和元素也是这样创建的。其中jsx()只不过是React.createElement 的语法糖而已, 元素或组件都会通过 React.createElement 创建返回一个 ReactElement 对象, 这是因为 React 利用 ReactElement 对象组成了一个 Javascript 对象树(也就是虚拟 DOM )。前面我进入了一个思维误区, 认为 memo 包裹的组件不会再被重新创建了, 其实不管是否有memo包裹, 都是会通过 React.createElement 来创建, 只不过被memo包裹的组件创建出来的 React 元素会有所不同, 具体的可以深入的学习 memo, 这里给大家推荐一篇文章《从源码学 API 系列之 React.memo》。

因此对于 props.children 而言, 每次得到的都是 React.createElement(About) 返回的一个新对象, 这也是 Home 组件的 props 改变了的原因; 而我们使用 useRef, 创建了一个不会改变的对象赋值给 Home 组件的 props, 所以 Home 组件的 props 没有发生变化, 就不会重新渲染。

解决方案

解决这个问题, 除了使用 useRef 之外, 我们还可以定义一个变量, 提到 App 组件外, 也可以做到这个效果, 如下所示:

import { useState } from "react";
import Home from "./pages/Home";
import About from "./pages/About";// 在组件外定义变量
const about = <About />;function App() {const [count, setCount] = useState(0);console.log("App is render");return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>Increment</button><Home>{about}</Home></div>);
}

当 About 组件没有依赖于 App 组件中其他状态时, 我们可以采用上面的做法, 但是如果 About 组件还依赖 App 内的其他状态, 可以发现无论是提变量还是 useRef 的做法都无法实现, 例如 About 组件中接收一个 name 参数, 由 App 组件传入:

import React, { memo } from "react";// 接收一个props.name
const About = memo(({ name }) => {console.log("About is render");return <div>About: {name}</div>;
});export default About;

这个时候我们就需要借助于 useMemo 进行优化(不用 useCallback 的原因是 useCallback 作用于函数, useMemo 作用于返回值, 在这里很明显我们想要作用于函数返回的组件), 就做到了实现当 count 发生变化时, 只有 App 组件重新渲染, 而 name 属性变化时 App、Home、About 都会重新渲染:

function App() {const [count, setCount] = useState(0);// 传入About组件的状态const [name, setName] = useState("Hello");// 使用useMemo优化const about = useMemo(() => <About name={name} />, [name]);console.log("App is render");return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>Increment</button><button onClick={() => setName("abc")}>Change Name</button><Home>{about}</Home></div>);
}
http://www.yayakq.cn/news/209206/

相关文章:

  • 做医疗科普的网站上海建设工程信息网查询
  • 柳城企业网站制作哪家好公众号开发者id在哪
  • 官网查询网站某颜值女主播低俗内容流出视频
  • 摄影网站开发的背景南昌网站建设q479185700惠
  • 请别人做网站需要注意什么问题网站建设域名是什么
  • 用花生壳做映射的网站需要备案家电设计网站
  • 怎么把网站黑掉郑州客串seo
  • wap网站设计业务型网站首页
  • 东莞网站推广排行wordpress的模板修改在哪个文件夹
  • 网站建设合同交印花税吗怎么提升网站的流量吗
  • 手机电子商务网站建设问卷调查关键词推广排名软件
  • 小型静态网站是什么原因你是网站设计有限公司的项目经理
  • php网站开发实例教程码源营销顾问
  • 口红机网站怎么做的上海二手房
  • 专业做商铺的网站便宜的做网站公司
  • 门户网站建设流程求个网站知乎
  • 给宝宝做衣服网站好各大浏览器的网址
  • react用于网站开发wordpress博客主题汉化
  • 做百度竞价对网站空间有什么要求网站建设及政务公开工作总结
  • 大庆市住房和城乡建设局网站wordpress完成静态化
  • 网站后台做数据库备份代码网站开发的推荐
  • 网站结构和布局区别logo网站素材
  • php网站开发设计网易企业邮箱怎么设置
  • 做网站容易还是app电商后台管理系统
  • 深圳网站建设的网站建设难度大吗
  • 网站建设课程报告论文网络营销的定义和内容
  • 06627网页制作与网站建设扁平 网站 模板
  • 门窗卫浴网站建设计算机考试网页制作怎么做
  • 免费做淘宝联盟网站长安大学门户网站是谁给做的
  • 自己做的网站算广告吗全国黄页平台