这段代码有问题吗?这段代码有什么问题:this.setState((prevState,props)=>{return{streak:prevState.streak+props.count,};});答:没有错。这种方法很少使用。我们可以传递一个函数给setState,它接收前一个状态的值和当前的props,并返回一个新的状态。如果我们需要根据之前的状态重新设置状态,推荐使用这种方式。HOC相对于mixins有哪些优势?Mixins在HOC和Vue中的作用是一样的,React早期也是用mixins的。但是使用class方法创建组件后,不能使用mixins方法了,其实mixins也存在一些问题,比如:隐含了一些依赖,比如我在组件里面写了某个state,然后在里面使用mixin是的,有一个依赖。万一下次有人要去掉,就得去mixin中找可能存在于多个mixin中的同名函数,同时同名函数不能出现在代码组件中,否则它将被重写。其实我一直觉得命名真的很麻烦。.滚雪球效应,虽然我还是对一个组件使用相同的mixin,但是一个mixin会被多个组件使用,可能需要让mixin修改原来的功能或者增加更多的功能,这可能会造成维护成本HOC解决这些问题,和他们达到的效果是一致的,同时,更政治正确(毕竟更实用)。哪些方法会触发React重新渲染?render又做了什么?(1)哪些方法会触发react重新渲染?setState()方法被调用。setState是React中最常用的命令。通常,执行setState会触发render。但这里有一点值得关注。执行setState时,不一定会重新渲染。当setState传null时,render不会被触发。类App扩展了React。组件{state={a:1};渲染(){控制台。日志(“渲染”);return({this.state.a}
{this.setState({a:1});//这里不改变值ofa}}>Clickmethis.setState(null)}>setStatenull);}}父组件重新渲染只要父组件重新渲染,即使传入子组件的props没有改变,那么子组件也会重新渲染,然后触发render(2)会怎样重新渲染渲染呢?它会比较新旧VNodes,也就是我们所说的Diff算法。对新老树进行一次深度优先遍历,这样每个节点都会有一个标记。深度遍历时,每遍历一个结点,将该结点与新的结点树进行比较。如果有差异,则将其放入一个对象中,遍历差异对象,根据差异类型更新VNodeReact处理render,并根据相应的规则更新VNodeReact处理render。基本的思维模式是每次有变化就重新渲染整个应用。在VirtualDOM出现之前,最简单的方式就是直接调用innerHTML。VirtualDOM的伟大之处不在于它比直接操作DOM更快,而在于无论数据如何变化,它都会尝试以最小的代价更新DOM。React将渲染函数返回的虚拟DOM树与旧树进行比较,以确定是否以及如何更新DOM。当DOM树很大时,遍历两棵树进行各种比较是相当耗费性能的,尤其是顶层setState的一个小变化,默认会遍历整棵树。尽管React使用了高度优化的Diff算法,但这个过程仍然会消耗性能。React上下文的理解在React中,数据传输一般使用props来传输数据,保持一种单向的数据流,可以让组件之间的关系变得简单和可预测,但是单项数据流在某些场景下并不适用。传递一对简单的父子组件是没有问题的,但是如果组件之间的依赖层次很深,就需要逐层传递props。显然,这太麻烦了。Context提供了一种在组件之间共享此类值的方法,而无需通过组件树的层显式传递props。上下文可以被视为特定组件树中用于数据传输的共享存储。简单来说,当你不想在组件树中通过props或state逐层传递的方式传递数据时,可以使用Context来实现跨层级的组件数据传递。JS代码块在执行过程中,会创建对应的作用域链。这个作用域链记录了运行时JS代码块执行过程中可以访问到的活动对象,包括变量和函数。JS程序通过作用域链访问它们。代码块内部或外部的变量和函数。如果我们用JS的作用域链来类比的话,React组件提供的Context对象其实就像是一个提供给子组件访问的作用域,而Context对象的属性可以看作作用域上的活动对象。由于组件的Context由其父节点链上的所有组件通过getChildContext()返回的Context对象组成,组件可以通过Context访问其父组件链上所有节点组件提供的Context的属性。了解虚拟DOM?虚拟DOM主要做什么?虚拟DOM本身是什么?本质上,VirtualDom是一个JavaScript对象,它以对象的形式表示DOM结构。将页面的状态抽象成JS对象的形式,配合不同的渲染工具,让跨平台渲染成为可能。通过事务处理机制,将多次DOM修改的结果一次性更新到页面,从而有效减少页面渲染次数,减少DOM修改的重绘和重排次数,提高渲染性能。VirtualDOM是对DOM的抽象,这个对象是对DOM更轻量级的描述。它设计的初衷是为了更好的跨平台。例如,node.js没有DOM。如果要实现SSR,那么一种方式就是使用virtualdom,因为virtualdom本身就是一个js对象。在代码渲染到页面之前,vue或react会将代码转换为对象(虚拟DOM)。以对象的形式描述真实的DOM结构,最终渲染到页面。每次数据变化前,虚拟dom都会缓存一份。当变化发生时,当前的虚拟dom将与缓存的虚拟dom进行比较。vue或者react内部封装了diff算法,通过这个算法比较,在渲染时修改变化的变化,通过原始数据渲染没有变化的原始数据。另外,现代前端框架的一个基本要求就是不需要手动操作DOM。一方面,手动操作DOM并不能保证程序的性能。如果在多人协作项目中审查不严格,一些开发人员可能会写出性能较低的代码。另一方面,更重要的是,省略手动DOM操作可以大大提高开发效率。为什么使用VirtualDOM:(1)保证性能下限,无需人工优化即可提供不错的性能。下面我们对比一下真实DOM操作和VirtualDOM在修改DOM时的过程,看看它们的重排和重绘。性能消耗:RealDOM:生成HTML字符串+重建所有DOM元素VirtualDOM:生成vNode+DOMDiff+必要的DOM更新VirtualDOM准备更新DOM需要更多的时间,也就是JS层面,相比其对DOM的消耗操纵是非常便宜的。游玉玺在社区论坛上说:框架给你的保证是我在没有人为优化的情况下依然可以给你提供不错的性能。(2)跨平台VirtualDOM本质上是一个JavaScript对象,可以方便的跨平台操作,比如服务端渲染,uniapp等,调用setState会发生什么?**当调用setState时,React做的第一件事是将传递给setState的对象合并到组件的当前状态中,这会启动一个称为协调的过程。协调的最终目标是以最有效的方式根据这个新状态更新DOM。为此,React将构建一个新的React虚拟DOM树(将其视为页面DOM元素的对象表示)。一旦你有了这棵DOM树,React就会将这棵新树与之前的虚拟DOM树进行比较,以确定DOM如何响应新状态而发生变化。通过这样做,React可以准确地知道发生了什么变化,并且可以在知道发生了什么变化后在绝对必要时通过更新DOM来最小化操作DOM所占用的空间。详细答案参考前端进阶面试题。钩子将值从父母传递给孩子。使用useState在父组件中声明数据。const[data,setData]=useState(false)向子组件传递数据child组件接收exportdefaultfunction(props){const{data}=propsconsole.log(data)父传子传父可以通过事件方法传值,有点类似于父传子。在父组件中使用useState声明数据const[data,setData]=useState(false)并将更新数据的函数传递给子组件在子组件中触发函数更新数据组件,会直接传给父组件exportdefaultfunction(props){const{setData}=propssetData(true)}如果有多级数据传输,也可以按照这个方法依次传输//多级使用useContextconstUser=()=>{//不回调直接获取const{user,setUser}=useContext(UserContext);return;};Presentationalcomponent和Containercomponent之间presentationalcomponents有什么区别,关心的是组件长什么样子。Display专门通过props接受数据和回调,很少有自己的状态,但是当展示组件有自己的状态时,它们通常只关心UI的状态而不关心数据的状态。容器组件更关心组件如何工作。容器组件向展示组件或其他容器组件提供数据和行为,它们调用Flux操作并将它们作为回调提供给展示组件。容器组件通常是有状态的,因为它们是(其他组件的)数据源。React性能优化在哪个生命周期?它的优化原理是什么?react父组件的render函数的重新渲染,会引起子组件的render方法的重新渲染。但是,有时子组件的父组件接收到的数据并没有改变。subcomponentrender的执行会影响性能,可以使用shouldComponentUpdate来解决这个问题。使用方法如下:shouldComponentUpdate(nexrProps){if(this.props.num===nexrProps.num){returnfalse}returntrue;}shouldComponentUpdate提供了两个参数nextProps和nextState,表示下一个props的值和一个state,当函数返回false时,render()方法不执行,组件不会被渲染,当返回true时,组件会照常重新渲染。此方法是将当前道具中的值与下一个道具中的值进行比较。当数据相等时返回false,否则返回true。需要注意的是,新旧比较时是浅比较,也就是说,如果比较的数据是指数据类型,只要数据的引用地址没有改变,即使内容发生变化,则判定为真。面对这个问题,可以使用以下方法解决:(1)在使用setState更改数据之前,先使用ES6中的assgin进行拷贝,但是assgin只对第一层数据进行深拷贝,所以不是最完美的方案:consto2=Object.assign({},this.state.obj)o2.student.count='00000';this.setState({obj:o2,})(2)使用JSON.parse(JSON.stringfy())进行深拷贝,但是当dataundefined遇到函数时会报错。consto2=JSON.parse(JSON.stringify(this.state.obj))o2.student.count='00000';this.setState({obj:o2,})类组件和函数组件有什么异同?相似之处:组件是React中最小的可重用代码片段,它返回要在页面上呈现的React元素。也正是因为组件是React的最小编码单元,所以不管是函数组件还是类组件,用法和最终渲染效果是完全一致的。我们甚至可以将类组件重写为函数组件,或者将函数组件重写为类组件(虽然不推荐这种重构行为)。从用户的角度来看,很难从用户体验上区分两者,而在现代浏览器中,闭包和类的性能只有在极端场景下才会有显着差异。因此,基本上可以认为两者作为组件是完全一致的。区别:他们在开发的心智模型上存在巨大差异。类组件基于面向对象编程,着重于继承、生命周期等核心概念;而函数组件的核心是函数式编程,强调不可变、无副作用、引用透明。之前在使用场景中,如果有组件需要使用生命周期,那么主推的就是类组件;在设计模式中,如果需要使用继承,那么主推的就是类组件。但是现在由于ReactHooks的引入,生命周期概念的淡出,函数组件完全可以替代类组件。其次,继承并不是组件最好的设计模式。官方更偏爱“组合优于继承”的设计理念,因此类组件在这方面的优势也在逐渐淡出。在性能优化方面,类组件主要依靠shouldComponentUpdate阻塞渲染提升性能,而函数组件则依赖React.memo缓存渲染结果提升性能。从入门的角度来说,类组件更容易上手。从未来的趋势来看,由于ReactHooks的引入,功能组件成为未来社区提出的主要解决方案。在未来的时间分片和并发模式下,类组件由于生命周期带来的复杂性,不容易优化。函数组件本身轻量简单,在Hooks的基础上,提供了比以往更细粒度的逻辑组织和复用,更适合React未来的发展。React中setState的第二个参数有什么作用?setState的第二个参数是一个可选的回调函数。该回调函数将在组件重新渲染后执行。相当于在componentDidUpdate生命周期内执行。一般推荐使用componentDidUpdate代替该方法。在这个回调函数中,可以得到状态更新后的值:this.setState({key1:newState1,key2:newState2,...},callback)//第二个参数是redux状态更新后的回调函数completed用户发起操作后,dispatch根据类型发送action触发对应的reducer。reducer是一个纯函数,它接收旧状态和动作并返回新状态。通过subscribe(listener)侦听器分发更新。如何比较diff算法?仅用于同级比较,跨级dom不会被复用。不同类型的节点生成的dom树是不一样的。此时会直接销毁旧节点和后代节点,新创建的节点可以使用key对元素进行diff的过程提供线索以供重用。Single-nodediff单点diff有以下几种情况:相同的key和type表示如果key不同则节点可以复用,直接标记为删除节点,然后新建的节点有相同的key和不同的类型,节点和兄弟节点被标记为删除。,然后新建一个节点react强制刷新component.forceUpdate()一个不常用的生命周期方法,它的作用是强制刷新官网解释如下默认情况下,当组件的state或者props发生变化时,组件会重新渲染。如果render()方法依赖于其他数据,您可以调用forceUpdate()强制组件重新渲染。调用forceUpdate()将导致组件调用render()方法,该方法会跳过组件的shouldComponentUpdate()。但是,它的子组件会触发正常的生命周期方法,包括shouldComponentUpdate()方法。如果标记发生变化,React仍然只会更新DOM。通常,您应该避免使用forceUpdate()并在render()中使用this.props和this.state。shouldComponentUpdate在初始化和forceUpdate时不会执行如何使用React.createElement改写如下代码问题:constelement=(你好,rdhub.cn!);答:constelement=React.createElement('h1',{className:'greeting'},'你好,rdhub.cn!');React.Component和React.PureComponent的区别PureComponent代表一个纯组件,可以用来优化React程序,减少renderfunctions的执行次数,从而提高组件的性能。在React中,当prop或state发生变化时,可以通过在shouldComponentUpdate生命周期函数中执行returnfalse来阻止页面的更新,从而减少不必要的render执行。React.PureComponent会自动实现shouldComponentUpdate。而pureComponent中的shouldComponentUpdate()进行的是浅层比较,也就是说如果是引用数据类型的数据,只会比较是否不是同一个地址,不会比较这个地址中的数据是否是持续的。浅比较忽略属性和/或状态突变。实际上,数据引用指针并没有发生变化,数据发生变化时re??nder也不会被执行。如果需要重新渲染,需要重新打开空间参考数据。PureComponent一般用在一些纯显示组件上。使用pureComponent的好处:当组件更新时,如果组件的props或state没有发生变化,则不会触发render函数。省略了虚拟DOM的生成和比较过程,以达到提升性能的目的。这是因为React会自动进行浅比较。在React中,refs的作用是什么?Refs可用于获取对DOM节点或React组件的引用。何时使用refs的好例子是管理焦点/文本选择、触发命令动画或与第3方DOM库集成。您应该避免使用字符串引用和内联引用回调。React推荐使用Refs回调。setState之后发生了什么?(1)在代码中调用setState函数后,React会将传入的参数对象与组件当前状态合并,然后触发所谓的调和过程(Reconciliation)。(2)在reconciliation过程之后,React会根据新的state以相对高效的方式构建React元素树,并开始重新渲染整个UI界面;(3)React获取元素树后,React会自动计算新树和旧树的节点差值,然后根据差值最小化界面的重新渲染;(4)在差分计算算法上,React可以比较准确的知道哪些位置发生了变化,应该如何变化,保证了按需更新,而不是全部重新渲染。调用setState将导致React更新生命周期中的四个函数执行。shouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdatereactrouterimportReactfrom'react'import{render}from'react-dom'import{browserHistory,Router,Route,IndexRoute}from'react-router'importAppfrom'../components/App'importHomefrom'../components/Home'importAboutfrom'../components/About'importFeaturesfrom'../components/Features'render(//历史路由,document.getElementById('app'))render(,document.getElementById('app'))ReactRouter提供了routerWillLeave生命周期钩子,使得React组件可以拦截正在进行的重定向,或者在离开路由之前提示用户。routerWillLeave的返回值有以下两种:returnfalse取消跳转return返回提示信息,提示用户在离开路由之前进行确认。你能用TypeScript编写React应用程序吗?如何操作?(1)如果CreateReactApp项目还没有创建,直接用typescript创建一个CreateReactApp项目:npxcreate-react-appdemo--typescript(2)如果CreateReactApp项目已经创建,typescript需要引入到现有的一些项目中,通过命令将typescript引入到项目中:npminstall--savetypescript@types/node@types/react@types/react-dom@types/jest重命名任意JavaScript文件,后缀为项目中'.js'对于TypeScript文件,后缀为'.tsx'(例如src/index.js重命名为src/index.tsx)