nicenote/docs/interview/react.md

6.3 KiB
Raw Blame History

nav group
title path
面试 /interview
title order
💊 面试题库 6

React

google 出品的一款前端MVC框架将所有可视化模块组件化提升开发效率在前端界具有跨时代意义目前居于三大框架之首。

为什么选择 react 框架而不是原生js

  1. 提升复用率,组件化的开发形式代码的复用率更高,交付更快,拓展性更强
  2. 生态成熟目前基于react的生态圈比较完善可以更快提升开发的效率
  3. 相比较早年的js + jq的开发形式MVC结构能够更好的提升代码的易读性让开发更加清晰

什么是 fiber 架构

react 需要经历两个阶段:

  1. 将jsx转换成 AST 结构
  2. 新老ast结构进行比较让后更新渲染到页面上

16以前的版本是将更新渲染直接入栈出栈队列执行diff算法本质上是一种递归递归无法中断这种形式可能会由于IO堵塞从而导致页面卡顿丢帧。 而fiber架构有效的改良了这一点使用的是一种循环机制将整个任务渲染切片成无数个小任务发放到每个细分的时间节点中执行优先处理最紧急的任务有效降低了卡顿的情况发生。

image.png

hooks 相比较传统 class 组件的区别

优点

  1. 解决了 HOC 的嵌套问题,扁平式状态逻辑更加简洁
  2. 解决了类组件的 this指向问题
  3. 分割在不同生命周期的代码使得代码难以维护
  4. 降低代码的复用成本减少每个组件继承react.component,大大提升性能

缺点

  1. 额外的学习成本
  2. 没有类组件的生命周期也就没办法和ComponentUpdate一样获取组件上的新旧数据做比较

memo 和 PureComponent

理论上父组件状态更新但是传递给子组件的内容没更新子组件不应该重新渲染memo 和 PureComponent 都是为了减少父组件的刷新导致子组件的额外渲染,区别是 memo 针对的是函数组件PureComponent 针对的则是类组件。

class Component extends React.PureComponent {
  render() {
    return (
      <div>类组件</div>
    )
  }
}

const Component = React.memo(() => {
  return (
    <div>函数组件</div>
  )
})

useMeno

将计算结果缓存下来,一般使用在比较复杂的计算函数中,降低大量计算的时候时间和性能上的消耗。

import React, { useMemo, useEffect, useState } from 'react'

export default () => {
  const [data1, setData1] = useState(1)
  const [data2, setData2] = useState(1)

  const memo1 = useMemo(() => {
    console.log('执行memo')
    return data1
  }, [data1])

  const f2 = (() => {
    console.log('执行f2')
    return data2.toString()
  })()

  return (
    <div className="demo1">
      {memo1}
      <br/>
      {f2}
      <button onClick={() => setData1(data1 + 1)} >f1按钮</button>
      <button onClick={() => setData2(data2 + 1)} >F2按钮</button>
    </div>
  )
}

useCallback

基本上和 useMemo 代码逻辑是一样的只是useCallback 相比较 useMemo是将函数缓存下来防止执行其他操作的时候多次渲染消耗性能。需要搭配meno一起使用。

import React, { useEffect, useCallback, useState } from 'react'

const Btn = React.memo((props) => {
  const [txt1, setTxt1] = useState(0)
  const [txt2, setTxt2] = useState(0)

  useEffect(() => {
    setTxt1(txt1 + 1)
  },[props.fn1])

  useEffect(() => {
    setTxt2(txt2 + 1)
  }, [props.fn2])

  return (
    <div>
      使用了cb方法{txt1}
      <br/>
      没使用cb方法{txt2}
      <button onClick={() => props.fn1()} >按钮1</button>
      <button onClick={() => props.fn2()} >按钮2</button>
    </div>
  )
})

export default () => {
  const [data1, setData1] = useState(1)

  const fn1 = useCallback(() => {
    console.log('使用了回调缓存')
    setData1(data1 + 1)
  }, [])

  const fn2 = () => {
    setData1(data1 + 1)
  }

  return (
    <div className="demo1">
      数据变化{data1}
      <br/>
      <button onClick={fn1} >父级按钮</button>
      <Btn fn1={fn1} fn2={fn2} />
    </div>
  )
}

lazy

懒加载组件实现效果类似webpack 的 code spliting。

import React, { lazy, Suspense } from 'react'

const Comp = React.lazy(() => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(import(/*webpackChunkName:"OtherComponent"*/'./OtherComponent'))
    }, 2000)
  })
});


export default () =>  {
  return (
    <div>
      <p>下面是一个动态加载的组件</p>
      <Suspense fallback="loading...">
        <Comp />
      </Suspense>
    </div>
  );
}

拓展:懒渲染可以参考 react-visibility-observer ,在页面滚动到可视范围时才加载相应的内容

列表使用key属性

首先我们需要知道react的virtualDom的原理如果没有id作为标识的情况时渲染引擎会直接将它视为新的标签从而造成渲染的消耗以下例子中相比较添加了key属性来说多了两次更新和一次新增的额外渲染。

<ul>
  <li>Alen</li>
  <li>Bob</li>
</ul>

// 无key值
<ul>
  <li>Alen</li>
  <li>Bob</li>
  <li>Chris</li>
</ul>

// 有key值
<ul>
  <li>Alen</li>
  <li>Bob</li>
  <li>Chris</li>
</ul>

componentDidMount 和 ComponentWillMount 区别

componentWillMount

  1. 将要装载在render之前调用
  2. 可以在服务端被调用,也可以在浏览器端被调用;
  3. componentWillMount 每一个组件render之前立即调用

componentDidMount

  1. render之后并不会立即调用而是所有的子组件都render完之后才可以调用
  2. 装载完成在render之后调用
  3. 只能在浏览器端被调用在服务器端使用react的时候不会被调用

手写一个简单的 useState

const [type, setType] = useState(1)

function useState(initData) {
  let type = initData

  let setType = (val) => {
    type = val
  }

  return [
    type,
    setType
  ]
}

redux 的工作原理

redux 分为几个重要的概念1. store容器、2. state数据、3. action动作、4. reducer计算动作过程、5. dispatch事件分发

工作过程dispatch通过调用action执行一个事件store自动调用reducer对state进行变更state变更同时view也产生变化

参考文档

https://juejin.cn/post/6844903922453200904