react面试题

164 阅读25分钟

一、什么是react,你对react的了解有哪些

react是一个网页的框架,通过组件化的方式解决图层开发复用的问题,本质是组件化框架 他的核心思路是声明式、组件式和通用性 声明式的优势在于直观和组合 组件化的优势在于拆分和模块复用,可以更容易做到低耦合、高内聚 通用性在于一次学习,随处编写,比如React Native这里主要通过虚拟dom来保证 这使得React的适用范围更广,无论是web,Native、VR 但作为视图层的框架,React的劣势非常明显,它并没有对于开发提供一揽子的解决方案,在开始开发应用之前,需要向社区解决整合方案,虽然这一定程度上 促进了社区的繁荣,但也为开发者在技术选型和学习适用上造成一定的成本

二、为什么React要用jsx

jsx是一个javascript语法扩展,结构类似XML,jsx主要用于声明react元素,但react中并不强制使用jsx,即便使用了,也会在构建的过程中被babel插件编译成react.createElement,所以jsx更像是react.createElement的语法糖,所以从这里看出react团队并不像脱离JavaScript的提心结构,而是希望通过合理的组件配置来保持开发的纯粹性,又不至于具有很大的学习成本 接下来jsx与其他类型对比

  1. template: react团队认为模板是一种不利于开发的体现,因为他引入很多其他的概念比如模板语法,模板指令等,所以增加了学习的成本
  2. 模板字符串:模板字符串编写的结构会引起嵌套使整个结构变得复杂,并且优化代码提示也会变得困难重重,
  3. JXON:同样因为语法提示的问题,而被团队放弃

三、如何避免生命周期中的坑

  • 不要再不恰当的时机调用不合适的代码
  • 在需要调用时,不能忘了调用 挂载阶段:
  • constructor
  1. 是类组件通用的构造函数,用于初始化state,不要在这里去处理初始化以外的逻辑
  2. 可以省略
  • getDerivedStateFromProps
  1. 本函数的作用是使组件在props变化时更新state
  2. 在props被传入时,state发生变化时,forceUpdate被调用时触发
  3. 不要直接复制props到state,不要在props修改后修改state
  • unsafe_componentWillmount
  1. 用于组件将加载前做某些操作,但是目前被标记为弃用
  2. 因为在异步渲染的机制下,该方法可能被多次调用
  3. 一个常见错误是服务器与客户端同构渲染的时候,如果在该函数中发起请求,拉取数据,会在服务端和客户端分别发送一次请求,所以不希望在componentWillmount中发起异步
  • render函数
  1. render函数应该是一个纯函数,所以不需要在里面产生副作用,比如不要在里面修改state,因为修改state调用setState会触发渲染,渲染调用setState,然后渲染,会造成死循环
  2. 也不要在render中绑定事件,因为会被调用导致频繁调用并注册事件
  • componentDidMount
  1. 主要用于组件加载完成之后做某些操作,比如发起异步
  2. 其他场景下,比如react native情况下,执行componentDidMount并不一定预示着真实的dom节点已经被渲染完成 update阶段:
  • unsafe_componentWillReceiveProps
  1. 该方法已被弃用,因为也是违背了生命周期中的异步渲染问题
  2. 当getDirvedStateFromProps存在时将componentWillReceiveProps将不会被执行
  • getDerivedStateFromProps
  1. 上面写过
  • shouldComponentUpdate
  1. 该方法是通过返回true和false实现判断是否
  2. 此方法是在渲染之前的最后一道关卡, 这个函数中可以对比props和state的值然后判断是否需要更新
  • unsafe_componentWillUpdate 这个方法已经被弃用
  • getSnapshotBeforeUpdate
    该方法在已经准备渲染,都准备好了,但是dom渲染之前被调用,getSnapshotBeforeUpdate的返回值会作为componentDIdUpdate的第三个参数
  • componenttDidUpdate 渲染完成之后被调用,避免在这里setState避免照成死循环
  • componentWillUnmount 这里是被写在之前调用,这里别忘了将定时器给清除掉,不然会造成反复调用 重新渲染 函数组件:在任何情况下都会被重新渲染,使用memo优化 类组件:state发生改变时,props发生改变时 pureComponent:浅比较过程中确认有变更才会触发重新渲染 错误边界 是一种react组件 提供了两个方法
  1. getDerivedStateFormError 该方法用于捕获子组件的异常,然后将state中的hasEorror修改为true
  2. componentDidcatch当执行的时候,知道了错误,将错误日志提交到服务器
  3. render的时候根据是否发生错误,返回降级后的ui还是正确的ui
class ErrorBoundary extends React.Component{
  constructor (props) {
    super(props)
    this.state = {hasError:false}
  }
  static getDerivedStateFromError(error){
    // 更新state使下一次渲染能够显示降级后的ui
    return {hasError:true}
  }
  componentDidCatch(error, errorInfo){
    // 将凑五日志上报给服务器
    logErrorToMyServce(error, errorInfo)
  }
	render(){
    if(this.state.hasError){
      // 可以在这里自定义降级后的ui并且渲染
      return <>xxxx</>
    }else{
    	return props.children
  }
  
}


需要做到以下

  • 不要再不恰当的时机调用不合适的代码
  • 在需要调用时,不能忘了调用 以下其中情况容易造成生命周期中的坑, 第一种是getDerivedStateFromProps 不注意会将props复制给state,直接修改state,容易造成受控组件和非受控组件区分模糊 第二种是componentWillmount componentWillUpdate componentWillReceiveUpdate三种生命周期已被react标记为弃用,在以后的版本中都要慎用,能不用就不要用了,这三个函数中因为react更新渲染底层机制的原因,会导致他被多次调用 第三种是shouldComponentUpdate是在更新之前调用,在这里可以做一些性能优化的操作 第四种是componentWillMount需要将定时器清除 第五种是给根组件添加错误边界,让页面不至于被让用于看到一片白屏,所以一定要添加 注:react请求应该放在哪里 对于异步来说应该放在componentDidMount中操作, 从事件顺序上来说除了componetDidMount还可以有以下选择
  • constructor:可放,前提不承载业务逻辑
  • componentWillMount: 也可以放,但是也被弃用,所以不建议使用

四、React的类组件与函数组件有什么区别

类组件和函数组件两者的设计模式不同

相较于类组件:函数组件更易于测试 如果在不适用Recompose或者hooks的情况下,如需使用生命周期,那么就使用类组件,类组件可以实现继承, 性能优化依靠shouldComponentUpdate函数去阻断渲染 函数组件依靠useMemo的方法

在使用方式上,没有什么区别,他们都能正确渲染出页面 但是他们的模型不一样

  • 类组件是面向对象编程
  • 函数组件是函数式编程 使用场景上
  • 如果使用生命周期,使用继承就使用类组件
  • 如果想要简单易用,那么就主推函数组件 未来趋势是hooks 在优化上
  • 类组件使用shouldComponentUpdate阻断渲染
  • 函数组件使用memo的方式缓存结果,优化渲染

五、如何设计react组件

react组件应该从设计分类和工程实践进行探讨, 从设计上来讲主流的方案是展示组件和灵巧组件两种

  • 展示组件之中只有展示,仅用于展示内容,布局样式等操作减少重复代码一个非常经典的案例是对于ui组件的再次封装,如果未来有可能替换掉这个组件,可以非常简单的使用
  • 灵巧组件分为容器组件和高阶组件两种
  • 容器组件主要用于,做一些布局相关的内容,协调各布局之间的传参等
  • 高阶组件用于逻辑复用,链式调用,渲染劫持。比如可以用于Consumer的传参,当然高阶函数也有其缺陷,比如他会丢失静态函数,会让组件嵌套很多层,refs也在这里不能透传 从工程实践上看可以将组件按照目录结构划分、引入工程管理
  • 按照目录划分常用的是将单独的一个页面划分为一个目录,把复用性较高的一些组件单独封装成一个组件
  • 按照工程管理可以将页面划分为basic、container、hoc三种组件然后还有page
  • 将展示组件放在basic中
  • 将容器组件放在container中
  • 将高阶组件放在hoc中
  • 将外层目录放在page中

六、setState是同步更新还是异步更新

setState并非是真异步只是看起来像异步,通过isBetchingUpdates来判断是先存在state队列还是直接执行,如果是true则将需要执行的内容放到state队列中,如果是false则直接执行 那什么时候isBetchUpdates值为true呢,在react可以控制的地方他的值就为true, 比如

  • react生命周期
  • react的合成事件 什么时候isBetchUpdates值为false呢,在react控制不到的地方 比如
  • addEeventListener、setTimeout等 为什么要使用异步更新呢 一般认为setState使用异步是为了性能优化,减少渲染次数,react团队还补充了两点
  • 第一点是保持内部的一致性
  • 第二点是启用并发更新完成异步渲染

七、react是如何实现传参的

第一种情况是父与子之间的通信

  • 通过props由父组件向子组件传参,由子组件执行父组件传入的函数,实现状态提升从而达到子父传参 第二种情况是兄弟之间的通信
  • 通过他们共同的父组件作为容器跳板,同时使用父子传参从而实现兄弟之间的传参 第三种情况是多层级的组件通信
  • 从顶层向下层传递数据,比如路由的参数,全局共同的参数还有国际化语言包可以使用context Api中的 Provider和Consumer
  • 如果是两个毫不相关的组件就可以使用状态管理框架,比如redux,flux,mobx

八、列举一种react的状态管理工具

  • flux
  • store是数据的仓库,用于存储所有的数据,当store中的数据发生改变的时候,就会引发view的更新
  • action为数据的中央枢纽,当view层中调用action的时候,action就调用action然后改变store,
  • 在flux中他的store可能有多个
  • redux
  • redux使用的是单一数据流,整个应用的state被存储在一个object tree中,并且这个object tree只存在唯一的的一个store中
  • reducer为存函数,reducer为描述如何改变的状态树返回完整的store
  • state是只读的唯一改变state的方法就算触发action,按照这个流程redux的插件可以实现状态回溯
  • mobx
  • mobx实际上和vue非常相似

补充: 任何具备业务价值的web应用必要执行复杂逻辑比如ajax请求等异步工作,这类逻辑使函数在每次执行的过程中,产生不同的变化,这就是副作用 为什么redux会产生副作用

  1. 所有的事件都收拢到Action中去触发
  2. 所有的UI状态都交给Store去管理
  3. 所有的业务逻辑都交给Reducer去处理 这三个 内容都不能实现异步的效果 于是引入了两个解决副作用的方式 第一种是在dispatch中添加middleware中间层,拦截分发的Action添加额外行为比如异步处理

// thunk源码
function createThunkMiddleware(extraArgument){
  return({dispatch, getState}) => (next) => (action) => {
    if(typeof action === 'function'){
      retrun Action(dispatch, getState, extraArgument)
    }
    return next(action)
  }
}

const thunk = createThunkMiddleware()
thunk.withExtraArgument = createThunkMiddleware
export default thunk

第二种是允许reducer直接处理副作用 比如promise,loop

首先是flux使用单向数据流的形式组合react组件的应用状态,他分为四个部分,

  1. dispatch 2. store 3. action 4. view store存储上了数据层的所有数据当store发生变化时会引起数据层的更新,如果在view层调用acton就会让当前数据层发生更新从而实现数据变化 action会对所有的dispatch进行统一管理 flux是单向数据流,其优点是非常明确的数据流来源,不至于使逻辑混乱难以维护

第二个是redux redux是flux的简化设计版本,但是他吸收了flux的有点,也在flux的基础上进行了更改,比如flux可能有多个store,但是redux只能有一个store,他包含了三个内容

  1. reducer纯函数,用于描述状态的变化,返回完整的状态
  2. dispatch用于分发状态的变化
  3. action用于统一管理dispatch 所以在redux中处理副作用成了非常重要的事情, 处理副作用有两种方法 第一种方式是在middleware中添加中间层,当接收到dispatch中的时候,添加一些处理逻辑,比如redux-thunk、redux-promise,他可以允许redux处理异步的逻辑 第二种是允许在reducer中可以处理异步逻辑 社区提供了的两种非常好的解决方式国外是rematch国内是dva

第三个是mobx mobx实际上和mobx相似,他通过绑定数据的方式,改变仓库中的值,当值发生变化的时候通知页面重新渲染 mobx5之前用defineproperty mobx5之后使用proxy

八、虚拟dom是如何工作的

虚拟dom的工作原理是通过js对象模拟dom节点的信息,是为了防止xss注入攻击,提高代码抽象能力,避免直接操作dom节点,降低代码整体风险,所以引入了虚拟dom,在插件的作用下,在编译时,虚拟dom会被babel编译成react.createElement执行,执行后会生成一个plan-object他会描述自己的type、props等,plan-object通过树形结构组成一颗虚拟dom树,当状态发生变化时,将变更前后的虚拟dom进行差异化比较,这个过程才称为diff,生成的结果称为patch,计算之后会渲染patch完成会对真实dom进行替换,

  • 虚拟dom的优点是有效防止了xss攻击,改善大规模操作dom的性能,较低的成本实现跨平台开发
  • 虚拟dom的缺点是因为需要大规模存储真实dom,需要对每个dom节点都存储描述,所以比较耗内存

虚拟dom可以真实的dom变更,可以实现埋点统计和数据记录

九、与其他框架比较react的diff算法有什么不同

diff算法是只生成补丁的方式,主要用于在虚拟节点发生变化的时候,通过diff算法,对比新旧节点生成补丁,然后替换真实dom。 react触发更新的时机是setState和props发生了变化,或者调用hook相关的方法之后,此时触发的diff算法主要用的是深度优先遍历,传统的diff算法因为需要对所有的节点逐一对比所以效率较低, 于是react使用的是分治的,比对通过三种方式

  1. 树比对:应为网页中一般很少有跨层级的移动dom方式,这里采用的是同层级的对比
  2. 组件比对:如果组件是同一类型就进行树比对,如果不是就放入补丁中
  3. 元素比对:通过对比元素的type ,属性,key等生成补丁,补丁对应真实的dom节点 自react16起,引入了fiber架构,为了使所有的操作都可暂停、可回退,所有的节点都使用了fiberNode和fiberTree进行重构,fiberNode使用双链表的结构,可以直接找到兄弟节点和子节点以及父节点,当遍历发生中断的时候,只需要保留当前节点的索引,这样断点就是可以恢复的 在fiber机制下整个更新过程由current和workinProgress两棵树双缓冲组成 ,workinProgress更新完成后再通过current相关指针指向新的节点 vue2和3的diff算法详情请看react补充之diff算法

十、React的渲染流程 第一个版本是stack Reconciler 是React15及之前版本的渲染方案,其核心是以递归的方式足迹调度栈中的子节点到父节点的渲染 第二个版本是fiber Reconciler 是React16及其之后版本的渲染方案,核心设计是增量渲染, 将渲染工作分割为多个区块,将其分散到多个帧中执行 react渲染流程大体一致,但是协调并不相同,以react16为分界线,分为stack Reconciler 和 fiber Reconciler其实就是diff算法不同, 具体内容需要看本章节的<02>. React渲染流程

十一、如何处理react渲染异常

react渲染异常的时候,如果做任何处理的情况下,就会出现错误无法处理,白屏的情况,原因是如果在javascript层出现错误使整个应用崩溃,。 所以在处理异常我们使用两种方案

  1. 预防,引入空安全相关的方案,使用typescript预防,在3.7之后可以使用可选链操作符
  2. 兜底,使用兜底的高阶组件,封装成了内部的npm包,在团队内部使用,通过量化结果统计报错,然后再通过这些报错修改bug

十二、react如何渲染长列表

有以下几种方案 首先后端不能一次性发送所有的数据,可以使用数据流的形式

  • 分页,每页展示相应的数据,可以将数据保存在本地也可以向后端发送请求,到第几页就渲染相应的内容
  • 懒加载,渲染可视区的内容,当页面滚动到底的时候,渲染相应内容 使用react-virulized 虚拟滚动 填入长度,窗口大小,条数,将列传入rowRender
import { List } from "react-virtualized";
const data = [1,2,3,4,5];

<List
    // 窗口的高度,必填
    height={400}
    // 窗口的宽度,必填
    width={300}
    // 总共个数
    rowCount={data.length}
    // cell高度
    rowHeight={30}
    style={{ outline: "none" }}
    rowRenderer={({ key, index, isScrolling, style }) => {
        if(isScrolling){ return <div key={ key } style={ style }>滚动中...</div> }
        return <div key={ key } style={ style }>{ data[index] }</div>
    }}
</List>

十三、react如何避免重复渲染

工具:react profiler 通常的解决方案是使用pureComponents、或者是使用react.memo等组件,缓存api减少重新渲染 但是错误的使用方式会使其完全无效,再jsx的属性中使用箭头函数,或者每次都生成新的对象, 有三个解决方案:

  1. 通过useMemo,useCallback缓存函数来产生结果,避免生成新的对象
  2. 使用不可变数据,使用immutablejs和immerjs使数据不发生改变
  3. 手动控制,自己使用shouldComponentUpdate

十四、怎么增加代码的可维护性

可分析性:

  • 目标:快速定位线上问题
  • 预防:人工code Review,lint工具校验
  • 兜底:sourcemap定位 可改变性:
  • 目标:代码易于维护拓展
  • 设计模式:组件设计模式
  • 状态管理框架 稳定性:
  • 目标:比秒修改代码硬气不必要的线上问题
  • 核心业务覆盖单元测试 易测试性:
  • 最好是使用函数式组件,类组件因为自己具有状态,而且状态容易发生改变,所以非常不容易维护 加强工具的使用
  • TypeScript
  • esLint 代码规范检查器
  • styleLint css规范检查器
  • commitlint 前端代码提交规范
  • editorconfig
  • prettier 代码自动排版

十四、为什么要使用hooks

  1. 类组件this指向很难获得,因为类在运行的时候会产生自己的实例,自己内部可以实现状态变化,于是很难维护
  2. 类组件在类的内部很难做到优化,

hooks使用限制

  1. 不要在循环、条件、嵌套函数中调用hook
  2. 不要在react函数组件之外调用hook

十五、useEffect 和 useLayoutEffect

共同点:底层的函数签名都是一样的,都是用于处理副作用 不同点: useEffect适用于大部分场景,因为是异步调用的原因,可以处理一些异步的副作用 useLayoutEffect:适用于处理dom,调整样式,避免页面闪烁,因为他是在dom节点更新之前调用的

十六、react-router路由

实现原理:基础原理 hash路由是依靠hash值变化网页不发生跳转的原理实现的,依靠hashchange这个api拿到当前的hash值,匹配是否正确,然后跳转到相应的页面 history:路由是依靠html5新增的一个api history Api 两个方法pushstate和replacestate实现跳转,popstate实现对页面路径的监听,实现路由跳转,使用这个api的时候,需要完成后端对historyApiFallback的配置

十七、react的事件机制

react事件不是使用addlistenner实现事件监听,而是使用手动冒泡,通过parentNode向上定位 react事件机制分为以下四个阶段

  1. 绑定阶段

  2. 事件合成

  3. 收集事件

  4. 触发事件回调函数

  5. 在本dom节点上添加一个仓库 store store中保存事件的处理函数

  6. 在document上添加事件处理函数,函数为react的合成事件

  7. 在合成事件中,react会模拟事件冒泡,一层一层向上查找,再从dom节点上查找store,有就查找store上的事件处理函数,如果事件名和本事件名一样,就执行,一直冒泡到顶层

十八、react中的key有什么作用

和vue一样,是在组件更新的时候的diff算法问题,diff算会考虑元素复用,先对比type,然后属性,如果一样就对比key,如果key一样就可以复用。如果使用index就会出现错乱的情况

十九、react中的ref作用是什么,原理是

定义: 类中:this.createRef hooks:useRef 如果定义在dom节点是可以直接获取到真实的dom节点 如果定义在类上,可以直接获取到类的实例 不能定义在函数上,如果想要定义在函数组件上,需要使用forword转发ref 常用于控制媒体控件,操作真实dom

二十、高阶函数

什么是高阶函数

  • 接收一个函数
  • 返回一个函数 解决什么问题 逻辑复用,给props添加更多的内容,可以提供一些额外的内容,比如生命周期,可以控制渲染,比如redux更新数据之后就是使用connect控制更新 如何编写高阶组件
  • 强化props,将props原封不动传入的情况下,添加其他的props比如路径,比如readux的全局内容
  • 控制渲染,比如在这里校验权限,如果权限不够的话就进行隔离,就不渲染了,比如在redux更新之后控制其重新渲染
  • 赋能组件,比如转发ref帮助组件实现对实例的控制,劫持组件添加生命周期

二一、如何写css

一是直接引用css,但是这种会造成全局污染的问题 二是使用modules,实行模块化,但是有个缺点是只能使用元素,但是不能实现对类的控制 三是使用其他的编译语言,scss和less,如果是嵌套的话就用global

二二、 组件如何做过渡动画

使用react-transition-group,他提供了三个主要组件

  • CSSTransition:结合css完成过渡动画
  • SwitchTransition:组件显示和隐藏,使用该组件
  • TransitionGroup:列表元素中的动画 CSSTransition使用 实际上就是给类添加,然后自己在css中定义
<CSSTransition in={inProp} timeout={200} classNames="my-node">
  <div>
    {"I'll receive my-node-* classes"}
  </div>
</CSSTransition>

  // 淡入淡出
.my-node-enter {
  opacity: 0;
}
.my-node-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.my-node-exit {
  opacity: 1;
}
.my-node-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}

SwitchTransition使用

  • mode属性控制怎么移动 out-in / in-out TransitionGroup直接使用,将需要动画的组件包含 他的原理是 插入节点,先渲染dom再动画 删除节点,先动画,再删除

二三、react-redux使用及原理

redux是全局处理状态的包,用于实现数据共享,全局状态分发 他秩序遵从几个原则,

  • 是单向数据流,即组件能获取到数据,store中不能获取组件
  • state是只读的,唯一修改数据的方法是通过dispatch
  • 使用reducer纯函数,修改state 他的流程是,当我们需要修改state中的值的话
  1. 需要actions中保存所有修改state的方法
  2. 通过dispatch分发action,然后传递到reducer中,通过reducer修改state的值,然后完整修改state
  3. 通过subscribe监听数据的变化,然后将组件重新渲染 redux工程化
  4. reducer为纯函数,保存初始状态,通过combineReducer完成对reducer的合并,
  5. action-types保存dispatch中key的名称,为唯一值,不重复
  6. actions文件中保存所有执行dispatch分发的函数 4, 使用react-redux中的provider传入store,
  7. 使用connect的mapState和mapActions两种方式完成传递props参数 redux原理
  8. 执行createStore的时候会创建一个空仓库state赋值为undefined,创建三个函数
  • getState就是将state返回
  • dispatch就是调用reducer
  • subscribe用于执行当值发生改变时调用回调函数
  1. 执行dispatch,传入一个基本不可能action,dispatch调用reducer,传入state和action,由于state一开始为undefined,那么函数就使用默认值得方式,将默认值提取,返回出来,赋值给state,等下一次调用reducer的时候state就是有值的,于是,就不使用初始值了,dispatch执行完毕之后需要将所有subscribe中保存的回调函数拿出来执行一次
  2. 定义subscribe实际上就是在容器中将回调函数添加进去,返回一个删除fn的方法,执行就删除此回调函数 我觉得在getState的过程中有一点做的不好,就是他直接返回了原始的对象,这就产生了一个bug就是如果直接修改堆中的值,所有人是都不知道的。后面虽然redux进行了处理就是如果直接修改会报错,值发生巨变,但是不如使用深拷贝的方式,返回拷贝之后的state。 全局状态管理拓展 flux是facebook内部使用的状态管理工具,属于redux的前生,基本上redux所有的理念都是借鉴flux,与redux不同的是flux使用的是多object Tree 而redux是单一的object Tree,而且优化了流程 mobx是类似于vuex的状态管理工具,和vuex一样使用数据双向绑定,当发生变化时直接调用并重新渲染,使用是直接绑定即可

二四、redux的中间件有哪些,原理是什么

redux的中间件有redux-promise、redux-thunk、redux-logger、redux-saga 原理是先将中间件放置到数组中,然后嵌套执行,patchThunk(patchPromise(dispatcj))

二五、redux解决中redux-promise、redux-thunk、redux-saga区别

共同点是他们都用于处理redux中的异步问题

  1. redux-thunk需要在action中进行异步操作,操作完成之后执行dispatch
  2. redux-promise隐藏了action的过程,将payload进行特殊处理,当调用的时候,会先进行异步请求,然后把异步结果作为payload,再同步触发action
import { getTodoByIdType } from "../types";

// 请求API
const getTodoById = async (payload) => {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${payload}`
  );
  const response = await res.json();
  return response;
};

// 直接将异步请求设置成payload
// 当异步有了结果会自动触发该action,然后进入到reducer更新state
export const getTodoByIdPromiseAction = (payload) => {
  return {
    type: getTodoByIdType,
    payload: getTodoById(payload),
  };
};
  1. redux-saga就是将异步的reducer抽离出来,当执行的时候,先进入saga的reducer,执行异步操作,当执行完毕之后再提交至普通的reducer执行修改操作

二六、react-router的使用

react-router有哪些标签

  • BrowserRouter / HashRouter
  • Route
  • Link / NavLisk
  • Switch
  • Redirect router6和router5有什么区别 Redirect改名为Navgiate,删除switch 新增了几个hooks useLocation useNavigate useRoutes

二七、react如何做优化

  • 使用shouldComponentUpdate、PureComponent、memo缓存组件使其不用重新渲染
  • 不要再render中引入多余的副作用
  • 避免使用内联函数
  • 使用React Fragument
  • 使用immutableJs缓存对象
  • 使用 lazy 和 susponse 配合 箭头函数导入组件懒加载
  • requestAnimationFrame或requestIdleCallback处理大量渲染问题

二八、react如何做服务端渲染

  1. 使用nextjs
  2. 监听端口号,当服务器接收到请求时,在当前的路由表里面查找数据,将数据作为props和context传入到组件中
  3. 调用react的renderToString,将组件渲染为html字符串,然后返回给客户端
  4. 客户端浏览器将html字符串渲染到页面上