写点什么

前端一面高频 react 面试题(持续更新中)

作者:beifeng1996
  • 2022-10-27
    浙江
  • 本文字数:5395 字

    阅读完需:约 18 分钟

如何避免组件的重新渲染?

React 中最常见的问题之一是组件不必要地重新渲染。React 提供了两个方法,在这些情况下非常有用:


  • React.memo():这可以防止不必要地重新渲染函数组件

  • PureComponent:这可以防止不必要地重新渲染类组件这两种方法都依赖于对传递给组件的props的浅比较,如果 props 没有改变,那么组件将不会重新渲染。虽然这两种工具都非常有用,但是浅比较会带来额外的性能损失,因此如果使用不当,这两种方法都会对性能产生负面影响。通过使用 React Profiler,可以在使用这些方法前后对性能进行测量,从而确保通过进行给定的更改来实际改进性能。

React 性能优化

  • shouldCompoentUpdate

  • pureComponent 自带 shouldCompoentUpdate 的浅比较优化

  • 结合 Immutable.js 达到最优

说说你用 react 有什么坑点?

1. JSX 做表达式判断时候,需要强转为 boolean 类型


如果不使用 !!b 进行强转数据类型,会在页面里面输出 0


render() {  const b = 0;  return <div>    {      !!b && <div>这是一段文本</div>    }  </div>}
复制代码


2. 尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃


3. 给组件添加 ref 时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的 prop 处理,让 ref 属性接受到新函数的时候,react 内部会先清空 ref,也就是会以 null 为回调参数先执行一次 ref 这个 props,然后在以该组件的实例执行一次 ref,所以用匿名函数做 ref 的时候,有的时候去 ref 赋值后的属性会取到 null


4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入

组件是什么?类是什么?类变编译成什么

  • 组件指的是页面的一部分,本质就是一个类,最本质就是一个构造函数

  • 类编译成构造函数

React 中 refs 的作用是什么

  • RefsReact 提供给我们的安全访问 DOM元素或者某个组件实例的句柄

  • 可以为元素添加ref属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回

在 Reducer 文件里,对于返回的结果,要注意哪些问题?

在 Reducer 文件里,对于返回的结果,必须要使用 Object.assign ( )来复制一份新的 state,否则页面不会跟着数据刷新。


return Object.assign({}, state, {  type: action.type,  shouldNotPaint: true,});
复制代码

setState 方法的第二个参数有什么用?使用它的目的是什么?

它是一个回调函数,当 setState 方法执行结束并重新渲染该组件时调用它。在工作中,更好的方式是使用 React 组件生命周期之——“存在期”的生命周期方法,而不是依赖这个回调函数。


export class App extends Component {  constructor(props) {    super(props);    this.state = {      username: "雨夜清荷",    };  }  render() {    return <div> {this.state.username}</div>;  }  componentDidMount() {    this.setstate(      {        username: "有课前端网",      },      () => console.log("re-rendered success. ")    );  }}
复制代码


参考:前端react面试题详细解答

shouldComponentUpdate 有什么用?为什么它很重要?

组件状态数据或者属性数据发生更新的时候,组件会进入存在期,视图会渲染更新。在生命周期方法 should ComponentUpdate 中,允许选择退出某些组件(和它们的子组件)的和解过程。和解的最终目标是根据新的状态,以最有效的方式更新用户界面。如果我们知道用户界面的某一部分不会改变,那么没有理由让 React 弄清楚它是否应该更新渲染。通过在 shouldComponentUpdate 方法中返回 false, React 将让当前组件及其所有子组件保持与当前组件状态相同。

传入 setstate 函数的第二个参数的作用是什么?

第二个参数是一个函数,该函数会在 setState 函数调用完成并且组件开始重渲染时调用,可以用该函数来监听渲染是否完成。


this.setstate(  {    username: "有课前端网",  },  () => console.log("re-rendered success. "));
复制代码

setState 是同步的还是异步的

有时表现出同步,有时表现出异步


  1. setState 只有在 React 自身的合成事件和钩子函数中是异步的,在原生事件和 setTimeout 中都是同步的

  2. setState 的异步并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的异步。当然可以通过 setState 的第二个参数中的 callback 拿到更新后的结果

  3. setState 的批量更新优化也是建立在异步(合成事件、钩子函数)之上的,在原生事件和 setTimeout 中不会批量更新,在异步中如果对同一个值进行多次 setState,setState 的批量更新策略会对其进行覆盖,去最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新


  • 合成事件中是异步

  • 钩子函数中的是异步

  • 原生事件中是同步

  • setTimeout 中是同步

说说 React 组件开发中关于作用域的常见问题。

在 EMAScript5 语法规范中,关于作用域的常见问题如下。(1)在 map 等方法的回调函数中,要绑定作用域 this(通过 bind 方法)。(2)父组件传递给子组件方法的作用域是父组件实例化对象,无法改变。(3)组件事件回调函数方法的作用域是组件实例化对象(绑定父组件提供的方法就是父组件实例化对象),无法改变。在 EMAScript6 语法规范中,关于作用域的常见问题如下。(1)当使用箭头函数作为 map 等方法的回调函数时,箭头函数的作用域是当前组件的实例化对象(即箭头函数的作用域是定义时的作用域),无须绑定作用域。(2)事件回调函数要绑定组件作用域。(3)父组件传递方法要绑定父组件作用域。总之,在 EMAScript6 语法规范中,组件方法的作用域是可以改变的。

概述一下 React 中的事件处理逻辑。

为了解决跨浏览器兼容性问题, React 会将浏览器原生事件( Browser Native Event)封装为合成事件( Synthetic Event)并传入设置的事件处理程序中。这里的合成事件提供了与原生事件相同的接口,不过它们屏蔽了底层浏览器的细节差异,保证了行为的一致性。另外, React 并没有直接将事件附着到子元素上,而是以单一事件监听器的方式将所有的事件发送到顶层进行处理(基于事件委托原理)。这样 React 在更新 DOM 时就不需要考虑如何处理附着在 DOM 上的事件监听器,最终达到优化性能的目的。

redux 中间件

中间件提供第三方插件的模式,自定义拦截 action -> reducer 的过程。变为 action -> middlewares -> reducer。这种机制可以让我们改变数据流,实现如异步actionaction 过滤,日志输出,异常报告等功能


  • redux-logger:提供日志输出

  • redux-thunk:处理异步操作

  • redux-promise:处理异步操作,actionCreator的返回值是promise

为什么虚拟 dom 会提高性能

虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能


具体实现步骤如下


  • JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中

  • 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异

  • 把 2 所记录的差异应用到步骤 1 所构建的真正的DOM树上,视图就更新


虚拟 DOM 一定会提高性能吗?


很多人认为虚拟 DOM 一定会提高性能,一定会更快,其实这个说法有点片面,因为虚拟 DOM 虽然会减少 DOM 操作,但也无法避免 DOM 操作


  • 它的优势是在于 diff 算法和批量处理策略,将所有的 DOM 操作搜集起来,一次性去改变真实的 DOM,但在首次渲染上,虚拟 DOM 会多了一层计算,消耗一些性能,所以有可能会比 html 渲染的要慢

  • 注意,虚拟 DOM 实际上是给我们找了一条最短,最近的路径,并不是说比 DOM 操作的更快,而是路径最简单

在 ReactNative 中,如何解决 8081 端口号被占用而提示无法访问的问题?

在运行 react-native start 时添加参数 port 8082;在 package.json 中修改“scripts”中的参数,添加端口号;修改项目下的 node_modules \react-native\local- cli\server\server.js 文件配置中的 default 端口值。

组件更新有几种方法

  • this.setState() 修改状态的时候 会更新组件

  • this.forceUpdate() 强制更新

  • 组件件 render 之后,子组件使用到父组件中状态,导致子组件的 props 属性发生改变的时候 也会触发子组件的更新

当渲染一个列表时,何为 key?设置 key 的目的是什么

Keys 会有助于 React 识别哪些 items 改变了,被添加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳定的标识,选择一个 key 的最佳方法是使用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会使用数据中的 IDs 作为 keys,当你没有稳定的 IDs 用于被渲染的 items 时,可以使用项目索引作为渲染项的 key,但这种方式并不推荐,如果 items 可以重新排序,就会导致 re-render 变慢。

React 高阶组件、Render props、hooks 有什么区别,为什么要不断迭代

这三者是目前 react 解决代码复用的主要方式:


  • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。

  • render props 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术,更具体的说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。

  • 通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个使用场景更加简单。这两种模式仍有用武之地,(例如,一个虚拟滚动条组件或许会有一个 renderltem 属性,或是一个可见的容器组件或许会有它自己的 DOM 结构)。但在大部分场景下,Hook 足够了,并且能够帮助减少嵌套。


(1)HOC 官方解释∶


高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。


简言之,HOC 是一种组件的设计模式,HOC 接受一个组件和额外的参数(如果需要),返回一个新的组件。HOC 是纯函数,没有副作用。


// hoc的定义function withSubscription(WrappedComponent, selectData) {  return class extends React.Component {    constructor(props) {      super(props);      this.state = {        data: selectData(DataSource, props)      };    }    // 一些通用的逻辑处理    render() {      // ... 并使用新数据渲染被包装的组件!      return <WrappedComponent data={this.state.data} {...this.props} />;    }  };
// 使用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
复制代码


HOC 的优缺点∶


  • 优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。

  • 缺点∶ hoc 传递给被包裹组件的 props 容易和被包裹后的组件重名,进而被覆盖


(2)Render props 官方解释∶


"render prop"是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术


具有 render prop 的组件接受一个返回 React 元素的函数,将 render 的渲染逻辑注入到组件内部。在这里,"render"的命名可以是任何其他有效的标识符。


// DataProvider组件内部的渲染逻辑如下class DataProvider extends React.Components {     state = {    name: 'Tom'  }
render() { return ( <div> <p>共享数据组件自己内部的渲染逻辑</p> { this.props.render(this.state) } </div> ); }}
// 调用方式<DataProvider render={data => ( <h1>Hello {data.name}</h1>)}/>

复制代码


由此可以看到,render props 的优缺点也很明显∶


  • 优点:数据共享、代码复用,将组件内的 state 作为 props 传递给调用者,将渲染逻辑交给调用者。

  • 缺点:无法在 return 语句外访问数据、嵌套写法不够优雅


(3)Hooks 官方解释∶


Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义 hook,可以复用代码逻辑。


// 自定义一个获取订阅数据的hookfunction useSubscription() {  const data = DataSource.getComments();  return [data];}// function CommentList(props) {  const {data} = props;  const [subData] = useSubscription();    ...}// 使用<CommentList data='hello' />
复制代码


以上可以看出,hook 解决了 hoc 的 prop 覆盖的问题,同时使用的方式解决了 render props 的嵌套地狱的问题。hook 的优点如下∶


  • 使用直观;

  • 解决 hoc 的 prop 重名问题;

  • 解决 render props 因共享数据 而出现嵌套地狱的问题;

  • 能在 return 之外使用数据的问题。


需要注意的是:hook 只能在组件顶层使用,不可在分支语句中使用。、

vue 或者 react 优化整体优化

  1. 虚拟 dom


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


虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。


用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的 DOM 树上,视图就更新了。

如何告诉 React 它应该编译生产环境版

通常情况下我们会使用 WebpackDefinePlugin 方法来将 NODE_ENV 变量值设置为 production。编译版本中 React会忽略 propType 验证以及其他的告警信息,同时还会降低代码库的大小,React 使用了 Uglify 插件来移除生产环境下不必要的注释等信息


用户头像

beifeng1996

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
前端一面高频react面试题(持续更新中)_React_beifeng1996_InfoQ写作社区