当前位置: 首页 > Web前端 > HTML

React前端常见面试题(持续更新中)

时间:2023-03-28 00:00:33 HTML

React组件如何做事件代理?它的原理是什么?React基于VirtualDOM实现了一个SyntheticEvent层(合成事件层)。定义的事件处理器会接收一个合成事件对象的实例,该对象符合W3C标准,与浏览器原生事件具有相同的接口,支持冒泡机制,所有事件自动绑定到最外层。在React底层,对于合成事件主要做了两件事:事件委托:React会将所有的事件绑定到结构的最外层,使用一个统一的事件监听器,它维护一个映射来保存所有组件内部的事件监听和处理功能。自动绑定:在React组件中,每个方法的上下文都会指向组件的实例,即this自动绑定到当前组件。如何有条件地向React组件添加props?对于某些属性,如果传递给它的值是假值,React会足够聪明地忽略该属性。例如:varInputComponent=React.createClass({render:function(){varrequired=true;vardisabled=false;return;},});渲染结果:另一种可能的方法是:varcondition=true;varcomponent=;react渲染过程中,兄弟节点是怎么处理的?也就是当key值不同的时候,通常我们在输出节点的时候,会映射一个数组,返回一个ReactNode。为了便于react内部优化,我们必须给每个reactNode添加一个key。此关键道具不按设计值开发。它被作者使用,但是用于反应。大概的作用就是给每个reactNode添加一个identity,方便react识别。在重新渲染过程中,如果key相同,如果组件属性发生变化,react只会更新组件对应的属性;如果没有变化,则不会更新。如果key不同,react会先销毁组件,然后重新创建组件。如何使用React构建(build)生产模式?通常,使用Webpack的DefinePlugin方法将NODEENV设置为生产环境。这将去除propType验证和额外的警告。除此之外,还可以减少代码,因为React使用了Uglify的死代码来消除开发代码和注释,这将大大减少包的占用空间。React中的元素和组件有什么区别?简单地说,React中的元素(虚拟DOM)描述了你在屏幕上看到的DOM元素。换句话说,React中的元素是页面中DOM元素的对象表示。React中的组件是接受输入并返回元素的函数或类。注意:在工作中,为了提高开发效率,通常使用JSX语法来表示React元素(虚拟DOM)。在编译时,将其转换为React.createElement调用方法。React老生命周期函数初始化阶段getDefaultProps:获取实例的默认属性getInitialState:获取各个实例的初始化状态componentWillMount:组件即将加载并渲染到页面上render:组件在这里生成一个虚拟DOM节点componentDidMount:组件实际正在加载加载后的运行状态componentWillReceiveProps:组件即将接收属性时调用shouldComponentUpdatecomponentWillUpdate:组件即将更新,不能修改属性和状态render:组件重绘componentDidUpdate:组件已更新在销毁阶段更新componentWillUnmount:即将销毁的组件diff算法是如何工作的详细答案参考前端高级面试题每个节点类型都有自己的Attributes,也就是props,每次diff是执行时,react会先比较节点类型,如果节点类型不同,那么react会直接删除这个节点,然后直接新建一个节点插入进去,如果节点类型相同,那么会比较prop是否有更新。如果prop不同,那么react会判断该节点已经更新,然后重新渲染该节点,然后逐层比较它的子节点,直到没有子节点为止。Redux中使用Action需要注意哪些问题?在Redux中使用Action时,Action文件中尽量保持Action文件的纯净,传入什么数据就返回什么。请求的数据最好和Action方法分开,以保持Action的纯净。React中setState的第二个参数有什么作用?setState的第二个参数是一个可选的回调函数。该回调函数将在组件重新渲染后执行。相当于在componentDidUpdate生命周期内执行。一般推荐使用componentDidUpdate代替该方法。在这个回调函数中,可以得到状态更新后的值:this.setState({key1:newState1,key2:newState2,...},callback)//第二个参数是状态更新完成后的回调函数在生命周期的哪一步应该发起AJAX请求?我们应该将AJAX请求放入componentDidMount函数中执行。主要原因是React的下一代协调算法Fiber会通过启动或停止渲染来优化应用程序性能,这会影响触发器的componentWillMount。componentWillMount生命周期函数的调用次数会变得不确定,React可能会频繁调用componentWillMount多次。如果我们把AJAX请求放在componentWillMount函数中,显然会被多次触发,不是一个好的选择。如果我们将AJAX请求放在生命周期的其他函数中,我们不能保证该请求只会在组件挂载后请求响应。如果我们的数据请求在组件挂载之前完成,调用setState函数将数据添加到组件状态,对于未挂载的组件会报错。而在componentDidMount函数中执行AJAX请求可以有效避免这个问题。React中批量更新setState的过程是怎样的?调用setState时,组件的状态不会立即发生变化,setState只是将要修改的状态放入一个队列中,React会优化真正的执行时机,并且出于性能考虑,React事件处理程序中的多个React的状态修改事件处理程序中的多个setState合并为一个状态修改。最终更新只会导致组件及其子组件的重新渲染,这对于大型应用程序的性能提升至关重要。this.setState({count:this.state.count+1===>入队,[count+1tasks]});this.setState({count:this.state.count+1===>入队,[计数+1个任务,计数+1个任务]});↓合并状态,[count+1task]↓执行count+1task。需要注意的是,只要同步代码还在执行,“saveup”就不会停止。(注:这里多次+1之所以只会生效一次,是因为同一个方法中的多个setState合并动作并不是简单的累加更新,比如这里对于同一个属性的设置,React只会保留最后一次更新)。Redux内部原理如何实现dispstch的一个功能以redux-thunk中间件为例,下面是thunkMiddleware函数的代码//部分转成ES5代码,运行中间件函数会返回一个新的函数,如下:return({dispatch,getState})=>{//next其实就是传入的dispatchreturnfunction(next){returnfunction(action){//redux-thunkcoreif(typeofaction==='function'){return动作(调度,getState,extraArgument);}返回下一个(动作);};};}redux-thunk库内部源码非常简单,允许action为函数,支持传参,否则调用方式不变。Redux创建Store:通过combineReducers函数合并reducer函数并返回一个新的函数组合(该函数负责循环reducer函数并返回所有状态)。将这个新函数作为参数传递给createStore函数。该函数使用dispatch来初始化和运行传入的组合,生成状态,并返回存储对象。使用了新的dispatch函数redux:其实就是通过循环遍历再次调用reducer函数,更新state高阶组件的应用场景权限控制。可以利用高阶组件的条件渲染特性来控制页面的权限控制。权限控制一般分为两种。维度:页面层级和页面元素层级this.setState({isAdmin:currentRole==='Admin',});}render(){if(this.state.isAdmin){return;}else{return(

您没有权限查看该页面,请联系管理员!
);}}};}//使用//pages/page-a.jsclassPageAextendsReact.Component{constructor(props){super(props);//这里有些东西...}componentWillMount(){//获取数据}render(){//使用数据渲染页面}}exportdefaultwithAdminAuth(PageA);你可能已经发现,高阶组件实际上是React中装饰器模式的实现:通过将组件(函数或类)传递给函数,在函数内部增强了组件(函数或类)的功能(不是在修改传入参数的前提下),最后返回这个组件(函数或类),它允许在不修改组件的情况下为已有的组件添加新的功能,是一种WrapperPattern什么是装饰器模式:动态添加在程序运行过程中,在不改变对象本身的情况下,对对象附加一些属性或行为,可以提高代码的可重用性和灵活性。高阶组件小总结:高阶组件不是组件,而是将一个组件转换为另一个组件的函数。高阶组件的主要作用是代码复用。高阶组件是React中的装饰器模式。EncapsulationPrinciple中封装组件的原则1.单一原则:负责单个页面渲染2.多重职责:负责多重职责,获取数据,复用逻辑,页面渲染等3.明确接受参数:必选,可选,尽量设置以_开头的参数,避免变量重复4.可扩展性:需求的变化可以及时调整,不影响之前的代码5.代码逻辑清晰6.封装的组件必须具备高性能和低耦合的特点7、组件单一职责:封装业务组件或基础组件。如果不能给这个组件起一个有意义的名字,就证明这个组件的职责可能不够单一。你需要不断地提取组件,直到它可以成为一个独立的组件,可以描述React中的事件。在处理方法上。为了解决跨浏览器兼容性问题,React中的事件处理程序将传递SyntheticEvent的实例,它是跨浏览器事件的包装器。这些SyntheticEvents具有与您习惯的本机事件相同的界面,并且它们在所有浏览器中都兼容。React实际上并没有将事件附加到子节点本身。相反,使用单个事件侦听器通过事件委托模式在顶层侦听所有事件。这对性能有好处。这也意味着React无需担心在DOM更新时跟踪事件监听器。当你想要配置webpack或babel预设时,什么会促使你摆脱create-react-app依赖。Reactdiff算法的原理是什么?diff算法其实讨论的是虚拟DOM树发生变化后生成DOM树更新补丁的方式。它比较新旧虚拟DOM树之间的变化,将更新补丁应用到真实的DOM上,以最小的代价完成视图更新。具体过程如下:首先将真实DOM映射到虚拟DOM;当虚拟DOM发生变化时,会根据间隙计算生成补丁。这个补丁是一个结构化数据,内容包括添加、更新、删除等;根据补丁更新真实DOM,反馈给用户界面。一个简单的例子:importReactfrom'react'exportdefaultclassExampleComponentextendsReact.Component{render(){if(this.props.isVisible){returnvisbile
;}返回隐藏
;}}在这里,首先假设ExampleComponent是可见的,然后改变它的状态使其不可见。映射到真正的DOM操作是React会创建一个div节点。visbile
当visbile的值为false时,会将class属性替换为hidden,并将内部的innerText重写为hidden。这种产生补丁和更新差异的过程统称为diff算法。diff算法可以概括为三种策略,分别从树、组件、元素三个层次优化复杂度:策略一:忽略节点跨层次操作场景,提高比较效率。(Tree-basedcomparison)这个策略需要树比较,也就是树的层次比较。树比较的处理方式非常“暴力”,即两棵树只比较同一层级的节点。如果发现某个节点不再存在,则该节点及其子节点将被彻底删除,不再使用。为了进一步比较,这提高了比较效率。策略二:如果组件的类相同,则默认为相似的树结构,否则默认为不同的树结构。(基于组件的比较)在组件比较的过程中:如果组件是同一类型,则进行树比较;如果没有,请将它们直接放入补丁中。只要父组件类型不同,就会重新渲染。这就是为什么shouldComponentUpdate、PureComponent和React.memo可以提高性能的原因。策略三:同级子节点可以通过标记key在链表中进行比较。(基于节点的比较)元素比较主要发生在同一层次,通过标记节点操作生成补丁。节点操作包括插入、移动、删除等,其中节点的重新排序涉及同时插入、移动、删除三个操作,因此效率消耗最大。这时候,策略三就起到了至关重要的作用。通过标记键,React可以直接移动DOM节点以减少内耗。传递给setstate函数的第二个参数的目的是什么?第二个参数是一个函数,当调用setState函数并且组件开始重新渲染时会调用该函数。您可以使用此功能来监视渲染是否完成。this.setstate({username:"游家前端网络",},()=>console.log("重新渲染成功。"));React组件的构造函数的作用是什么?有必要吗?构造函数主要用于两个目的:通过将对象赋值给this.state来初始化本地状态将事件处理方法绑定到实例所以,当你需要在React类中设置状态的初始值或者绑定事件时,需要添加构造函数,官方Demo:classLikeButtonextendsReact.Component{constructor(){super();this.state={喜欢:假};this.handleClick=this.handleClick.bind(this);}handleClick(){this.setState({liked:!this.state.liked});}render(){consttext=this.state.liked?'喜欢':'还没有喜欢';return(你{text}这个。点击切换。
);}}ReactDOM.render(,document.getElementById('example'));构造函数用于创建一个新的父类的this对象;子类必须在构造方法中调用super方法;否则新建实例会报错;因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行处理。如果你不调用super方法;子类不会得到这个对象。注意:constructor()必须和super()配对。如果你想在构造函数中使用this.props,你必须传入props。否则,您不需要在JavaScript中进行绑定。每次都会返回一个新函数。出于性能考虑,尽量在构造函数中使用为什么React中在绑定事件中使用refs?Refs提供了一种访问DOM节点或在render方法中创建的React元素的方法。在典型的数据流中,props是父子组件交互的唯一方式。要修改子组件,您需要重新渲染它。凡事都有例外。在某些情况下,我们需要强行修改典型数据流之外的子项。这时候就可以使用Refs了。我们可以给组件添加一个ref属性来使用。此属性的值是一个回调函数,它接收底层DOM元素或已安装的组件实例作为其第一个参数。classUnControlledFormextendsComponent{handleSubmit=()=>{console.log("InputValue:",this.input.value);};render(){return((this.input=input)}/>提交);}}注意input元素有一个ref属性,它的值是一个函数。此函数将实际的DOM元素作为输入并将其放置在实例上,以便可以在handleSubmit函数中访问它。人们经常误解refs只能在类组件中使用,但refs也可以通过利用JS中的闭包与函数组件一起使用。函数CustomForm({handleSubmit}){让inputElement;返回(handleSubmit(inputElement.value)}>(inputElement=input)}/>提交);}react-router4的核心路由变成组件分散到各个页面,没有等配置