第3节 react面试题(35道)#

01 react项目中有哪些难点#

02 react 与vue的区别#

https://www.jianshu.com/p/eb06903c8bf7

03 react 优化#

04 react 新特性#

1.context 可以跨组件传参 2.lazy、suspense 动态引入组件 3.memo 相当于 shouldComponentUpdate 使用在函数式组件中 4.hooks 同下

05 使用hooks#

在函数式组件中调用 state,调用钩子,  useState, useEffect

06 setstate是异步还是同步,setState之后发生了哪些事情#

  • setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。
  • setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

07 react生命周期钩子函数#

componentWillMount   去掉 render componentDidMount componentWillReceiveProps  去掉 shouldComponentUpdate   作用?函数式组件中  使用memo0 componentWillUpdate  去掉 componentDidUpdate componentWillUnmount

08 React 中 keys 的作用是什么?#

Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。 在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。

09 调用 setState 之后发生了什么?#

在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

10 react 生命周期函数#

初始化阶段: getDefaultProps:获取实例的默认属性 getInitialState:获取每个实例的初始化状态 componentWillMount:组件即将被装载、渲染到页面上 render:组件在这里生成虚拟的 DOM 节点 componentDidMount:组件真正在被装载之后 运行中状态: componentWillReceiveProps:组件将要接收到属性的时候调用 shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了) componentWillUpdate:组件即将更新不能修改属性和状态 render:组件重新描绘 componentDidUpdate:组件已经更新 销毁阶段: componentWillUnmount:组件即将销毁 V17.0之后的版本删除的钩子函数 componentWillMount ,componentWillReceiveProps ,componentWillUpdate 在 v16.3以上版本新增的钩子函数 getDerivedStateFromProps,getSnapshotBeforeUpdate

11 shouldComponentUpdate 是做什么的,#

(react 性能优化是哪个周期函数?) shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘 dom。因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。 参考react 性能优化-sf

12 为什么虚拟 dom 会提高性能?(必考)#

虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。 用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。 参考 如何理解虚拟 DOM?-zhihu

13 react diff 原理(常考,大厂必考)#

把树形结构按照层级分解,只比较同级元素。 给列表结构的每个单元添加唯一的 key 属性,方便比较。 React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字) 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制. 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。 参考:React 的 diff 算法

14 React 中 refs 的作用是什么?#

refs的适用情况: 1.处理焦点,文本选择,媒体控制 2.触发强制动画 3.继承第三方的dom库 4.如果可以通过声明能实现的,尽量避免使用refs Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回: class CustomForm extends Component { handleSubmit = () => { console.log("Input Value: ", this.input.value) } render () { return (

<input type='text' ref={(input) => this.input = input} /> Submit

) } } 上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。另外值得一提的是,refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值: function CustomForm ({handleSubmit}) { let inputElement return (

) }

15 如果你创建了类似于下面的 Twitter 元素,那么它相关的类定义是啥样子的?#

import React, { Component, PropTypes } from 'react' import fetchUser from 'twitter' class Twitter extends Component { state = { user: null, } static propTypes = { username: PropTypes.string.isRequired, } componentDidMount () { fetchUser(this.props.username) .then((user) => this.setState({user})) } render () { return this.props.children(this.state.user) } } 这种模式的优势在于将父组件与子组件解耦和,父组件可以直接访问子组件的内部状态而不需要再通过 Props 传递,这样父组件能够更为方便地控制子组件展示的 UI 界面。譬如产品经理让我们将原本展示的 Badge 替换为 Profile,我们可以轻易地修改下回调函数即可:

16 展示组件(Presentational component)和容器组件(Container component)之间有何不同#

展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。 容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。

17 类组件(Class component)和函数式组件(Functional component)之间有何不同#

类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态 当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 '无状态组件(stateless component)',可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件

18 (组件的)状态(state)和属性(props)之间有何不同#

State 是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。 Props(properties 的简写)则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据--回调函数也可以通过 props 传递。

19 何为受控组件(controlled component)#

在 HTML 中,类似 ,  这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。

20 何为高阶组件(higher order component)#

高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象。最常见的可能是 Redux 的 connect 函数。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC。

21 为什么建议传递给 setState 的参数是一个 callback 而不是一个对象#

因为 this.props 和 this.state 的更新可能是异步的,不能依赖它们的值去计算下一个 state。

22 除了在构造函数中绑定 this,还有其它方式吗#

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

23  (在构造函数中)调用 super(props) 的目的是什么#

在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。

24 应该在 React 组件的何处发起 Ajax 请求#

在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount 中发起网络请求将保证这有一个组件可以更新了。

25 描述事件在 React 中的处理方式。#

为了解决跨浏览器兼容性问题,您的 React 中的事件处理程序将传递 SyntheticEvent 的实例,它是 React 的浏览器本机事件的跨浏览器包装器。 这些 SyntheticEvent 与您习惯的原生事件具有相同的接口,除了它们在所有浏览器中都兼容。有趣的是,React 实际上并没有将事件附加到子节点本身。React 将使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的,这也意味着在更新 DOM 时,React 不需要担心跟踪事件监听器。

26 React 中有三种构建组件的方式#

React.createClass()、ES6 class 和无状态函数。

27 react 组件的划分业务组件技术组件?#

根据组件的职责通常把组件分为 UI 组件和容器组件。 UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。 两者通过 React-Redux 提供 connect 方法联系起来。

28 了解 redux 么,说一下 redux 把#

redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer,工作流程是 view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据,flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是 view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。Redux 和 Flux 很像。主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中 dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰 新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们 redux 有什么缺点 一个组件所需要的数据,必须由父组件传过来,而不能像 flux 中直接从 store 取。 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响,或者需要写复杂的 shouldComponentUpdate 进行判断。

29 setState 同步异步问题#

setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。 setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的, 只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到 更新后的值,形式了所谓的“异步”,当然可以通过第二个参数setState(partialState, callback)中的callback拿到更新后的结果。 setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件 和setTimeout中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多 个不同的值,在更新时会对其进行合并批量更新。 想要获取到正确的state的值,必须在 setState的第二个参数(回调函数)中,

30 react新特性#

context  可以跨组件传参,既从根节点可以直接传参到叶子节点 1.创建 const ThemeContext = React.createContext('light'); 2.传参

<ThemeContext.Provider value="dark">
      组件名
</ThemeContext.Provider>

3.接收

function MyButton(props){
  //3.接收参数
  return <ThemeContext.Consumer>{
    theme=><button className={theme}>按钮</button>
  }
  </ThemeContext.Consumer>
}

hooks 1.useState  可以在函数式组件中使用state ,并且可以调用函数更改state的值 2.useEffect useEffect它与 React 类中的 componentDidMount,componentDidUpdate,和 componentWillUnmount 有相同的功能,但是统一为单个 API。 memo 是在 函数式组件中,如果有组件不需要更新时,调用memo ,相当于 类组件中的 shouldComponentUpdate lazy\Suspense\错误边界(Error boundaries)

31 redux-saga 和redux-thunk的区别:#

redux-saga可以解决thunk 的两个问题: 1.action的形式不统一 2.就是异步操作太为分散,分散在了各个action中 不易维护 3.saga将异步操作放到统一的一个文件中处理

32 redux-saga的优缺点#

优点: (1)集中处理了所有的异步操作,异步接口部分一目了然 (2)action是普通对象,这跟redux同步的action一模一样 (3)通过Effect,方便异步接口的测试 (4)通过worker 和watcher可以实现非阻塞异步调用,并且同时可以实 现非阻塞调用下的事件监听 (5) 异步操作的流程是可以控制的,可以随时取消相应的异步操作。 缺点:太复杂,学习成本较高

33 redux-saga的effect (工具方法)#

put:对应的是middleware中的dispatch方法,可以发送一个动作 call: 表示异步调用,其中call表示的是阻塞调用, fork:表示异步调用,表示的是非阻塞调用。 take:监听action,返回监听到的action对象 delay:延时 takeEvery:予以相当于 on ,允许并发action all:创建effect的描述信息,用来命令中间件,并行多个effect,并等待他们全部完成

34 react 项目优化#

1.使用Fragment。减少不必要的节点生成,也可以使用空标签 2.类组件使用 shouldComponentUpdate,减少不必要的组件渲染 3.多使用 函数式组件渲染、减少使用类组件 4.函数式组件中使用 memo 避免重复渲染 5.使用React.lazy()和Suspense进行懒加载 6.异常捕获边界(Error Boundaries) 捕获发生异常的React组件。将异常组件和正常组件分割开。提高用户的体验性能。

  1. 骨架屏 骨架屏插件以react-content-loader(svg图片生层)为基础。用于在页面初始加载时,避免出现白屏现象。 8.长列表优化 虚拟化长列表:只加载可视范围内的数据。 当网站需要加载大批量数据(成千上万)时,会加载特别慢。 这个时候我们可以使用“虚拟滚动”技术(react-window或者react-virtualized),只渲染当前屏幕范围内的数据。 鼠标滚动去触发事件,再渲染一屏。
  2. 根据性能优化工具修改代码
  3. 使用Chrome的Performance工具
  4. React Devtools的Profiler工具分析; 通过React.Profiler组件包裹需要分析渲染时间的组件(不适合生产环境)。 10.SEO优化-预渲染 使用prerender-spa-plugin的puppeteer(无头浏览器)功能。 11.图片懒加载 使用react-lazyload插件 12.for循环中的key优化 13.在使用了定时器的页面,页面离开时,停止未完成的渲染 //解决 警告问题: Can't perform a React state update on an unmounted component.
  componentWillUnmount = () => {
    //停止定时器
    clearInterval(this.inter);
    //如果页面跳转时,setState还没有执行完,就停止它,return
      this.setState = (state,callback)=>{
        return;
      };
  }

35 react路由传参#

  1. params#

<Route path='/path/:name' component={Path}/>
<link to="/path/2">xxx</Link>
this.props.history.push({pathname:"/path/" + name});
读取参数用:this.props.match.params.name

优势 : 刷新地址栏,参数依然存在 缺点:只能传字符串,并且,如果传的值太多的话,url会变得长而丑陋。

  1. query#

<Route path='/query' component={Query}/>
<Link to={{ path : ' /query' , query : { name : 'sunny' }}}>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name

优势:传参优雅,传递参数可传对象; 缺点:参数地址栏不显示,刷新地址栏,参数丢失

  1. state#

<Route path='/sort ' component={Sort}/>
<Link to={{ path : ' /sort ' , state : { name : 'sunny' }}}> 
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
读取参数用: this.props.location.state.name

同query差不多,只是属性不一样,而且state传的参数是加密的

  1. search

<Route path='/web/departManange ' component={DepartManange}/>
<link to="web/departManange?tenantId=12121212">xxx</Link>
this.props.history.push({pathname:"/web/departManange?tenantId" + row.tenantId});
读取参数用: this.props.location.search

优缺点同params 

Logo

前往低代码交流专区

更多推荐