面试记录(React 相关)

251 阅读5分钟

响应式
虚拟DOM
组件化
生命周期
数据管理和传递
数据状态管理
hooks 相关

React 提供的核心技术

  • 响应式的 UI (ui = f(data))
  • 虚拟 DOM
  • 组件化

响应式 UI

关与响应式,你只需要关心你要什么,并且引用相关的数据,当数据发生改变的时候,React 会自动的更新 UI。

虚拟DOM

虚拟 DOM 在用户代码和真是 DOM 之间的桥梁,数据更新,会先触发虚拟DOM 改变,在将计算好的改变,一次性提交给真实 DOM,这样做可以提升性能。

组件化

  1. 是完整的对数据逻辑和功能的封装
  2. 提高代码的维护性

生命周期

React 为类组件提供了一系列的生命周期,以方便用户在某些时候可以做一些事情。
16.0+ 版本以后,react 的整个渲染过程可以分为两个阶段:

  1. Render 阶段:在这个阶段执行的生命周期函数都是无副作用的纯净函数,因为这个过程可能会被暂停,终止和重新执行。
  2. Commit 阶段:在这个阶段,React 已经开始提交 DOM,这个阶段不会被暂停或者终止,所以可以执行一些副作用的操作。

具体解析

这里将把生命周期分为初始渲染更新卸载 三个阶段并且配合上 React 的两个渲染阶段进行记录。

  1. 初始渲染

1.1 初始化渲染 Render阶段

  • constructor
  • static getDerivedStateFromProps(prveProps, state)
  • render

1.2 初始化渲染 Commit 阶段

  • componentDidMount: 此时 DOM 已经更新,可以做一些DOM操作或者副作用操作

注意:componentWillMount 已经被冷落,新的代码中最好不要使用

  1. 更新

2.1 更新 Render 阶段

  • static getDerivedStateFromProps(prveProps, state)
  • shouldComponentUpdate: 是否渲染的优化函数,更多参考React.PureComponent类组件 或者 React.Memo 函数组件
  • render

2.2 更新 Commit 阶段

  • getSpanshotBeforeUpdate(props,state): 注意,这里的 props 还没有和 this.props 合并,而且访问到的是还未更新的 DOM
  • componentDidUpdate
  1. 卸载
  • componentWillUnmoent: 组件卸载时执行,主要用来解除监听等。
  1. 额外需要关注的生命周期
  • componetCatchError(error, info): 用于捕获子组件在渲染过程中发生的同步任务,可以做日志记录。
  • static getDerivedStateFromError(error): 也用来捕获错误,并且返回值会合并进 state 中。

注意: 只要注册了上述两者之一得组件,都可称作为错误边界,只能捕获子组件在渲染期间发生的错误,不能捕获组件自身的错误。

数据管理和传递

  1. 组件自身可以通过 state(类组件)或者hooks(函数组件)来维护自身的状态
  2. 父子组件之间可以通过 props 进行数据传递,也可通过传递函数来使子组件控制父组件(违反了单向数据流,不推荐)
  3. 无关联组件之间可以通过 Context 或者状态管理库(redux,mobx等)进行数据状态管理

数据状态管理

  1. redux:这是 React 应用中,使用最广范的状态管理库,有完备的中间件机制和数据状态管理机制。
  2. mobx: 这是一个后起的状态管理库,提供了简介的 API,面向对象的方式创建 Store 和 多种自由的写法。

两者的共同点和区别

共同点:

  1. 它们都是统一管理应用状态

  2. 某一状态只有一个来源(Stroe 是唯一的数据来源)

  3. 操作更新状态的方式统一(都是通过 action 去触发跟新状态)

  4. 支持 StoreReactreact-reduxreact-mobx)连接,以此,通常可以把组件分为两种组件

    1. 容器组件:负责处理业务的数据和状态,将数据和状态传递给需要显示的组件
    2. 展示组件:负责展示视图,将的到的数据合理的展示出来

区别:

  1. redux 的编程范式规范,需要编写一些模板代码来创建整个数据流程。
  2. mobx 的没有固定的写法,相对来说比较自由,但在处理大应用时可能会有编程风格不统一的维护风险。
  3. 异步支持方面,redux 需要 redux-thunk 或者 redux-saga 的协助才能完成异步处理,而 mobx 则天生支持异步处理,不需要其他的工具库支持。
  4. 编程风格上,redux 仅支持纯函数,要求数据不可变,而 mobx 支持面对对象和函数式编程,状态的修改是直接在原状态对象上修改的。
  5. redux 只支持单一 storemobx 支持多 store

hooks 相关

  1. hooks 是 React 新添加的增强函数组件功能的 api。
  2. hooks 只能在 React 函数组件里面使用,不能再类组件和普通 js 函数中使用。
  3. hooks 只能定义在函数组件的最顶层区域,不能再 条件判断循环嵌套等会影响 hooks 执行顺序的语句中使用

主要 hooks 介绍

  1. useState

    1. 类似于 setState,主要是帮助函数组件获取和改变状态值
    2. 需要注意的是函数组件中的 state 每次更新都是独立的,这种特性是由 js 中的闭包决定的。
    function APP(props) {
        const [use, setUser] = useState('tom');
        
        useEffect(() => {
            setTimeout( () => {
                console.log(use); // 这里的结果是 tom
            }, 3000 );
        }, []);
        
        return (
            <div onClick={() => {setUser('merry')}}></div>
        )
        
    }
    

    上例中最终结果及时你点击过按钮更新了 use 结果是 tom

    1. 如果想访问上一次的 state,可以这么做
    setUser(use => use + "o" );
    
    1. useState 的参数就是初始化的 state 值,只会在初始化时执行一次。
    2. state 如果是个引用类型的值,需要每次更新时手动去合并,不然 React 会直接做覆盖。
  2. useEffect

    1. 这个钩子接收两个参数,第一个参数是个回调函数,第二个参数可以为空或者不传递。

      import React, { useState, useEffect } from 'react';
      function FriendStatus(props) {
        const [isOnline, setIsOnline] = useState(null);
      
        useEffect(() => {
          function handleStatusChange(status) {
            setIsOnline(status.isOnline);
          }
          ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
          // 返回值告诉了 react 需要去清理哪些操作
          return function cleanup() {
            ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
          };
        });
      
        if (isOnline === null) {
          return 'Loading...';
        }
        return isOnline ? 'Online' : 'Offline';
      }
      
    2. 第二个参数如果不传递,useEffect 相当于 DidMountDidUpodate。空数组相当于 DidMount。如果数组中包含 state,则会在初始化和相关 state 更新时执行回调函数。

    3. 回调函数的返回值会在每次回调函数执行前调用,基本过程是,先清除 -> 再注册

  3. 更多的钩子函数