一、什么是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与其他类型对比
- template: react团队认为模板是一种不利于开发的体现,因为他引入很多其他的概念比如模板语法,模板指令等,所以增加了学习的成本
- 模板字符串:模板字符串编写的结构会引起嵌套使整个结构变得复杂,并且优化代码提示也会变得困难重重,
- JXON:同样因为语法提示的问题,而被团队放弃
三、如何避免生命周期中的坑
- 不要再不恰当的时机调用不合适的代码
- 在需要调用时,不能忘了调用 挂载阶段:
- constructor
- 是类组件通用的构造函数,用于初始化state,不要在这里去处理初始化以外的逻辑
- 可以省略
- getDerivedStateFromProps
- 本函数的作用是使组件在props变化时更新state
- 在props被传入时,state发生变化时,forceUpdate被调用时触发
- 不要直接复制props到state,不要在props修改后修改state
- unsafe_componentWillmount
- 用于组件将加载前做某些操作,但是目前被标记为弃用
- 因为在异步渲染的机制下,该方法可能被多次调用
- 一个常见错误是服务器与客户端同构渲染的时候,如果在该函数中发起请求,拉取数据,会在服务端和客户端分别发送一次请求,所以不希望在componentWillmount中发起异步
- render函数
- render函数应该是一个纯函数,所以不需要在里面产生副作用,比如不要在里面修改state,因为修改state调用setState会触发渲染,渲染调用setState,然后渲染,会造成死循环
- 也不要在render中绑定事件,因为会被调用导致频繁调用并注册事件
- componentDidMount
- 主要用于组件加载完成之后做某些操作,比如发起异步
- 其他场景下,比如react native情况下,执行componentDidMount并不一定预示着真实的dom节点已经被渲染完成 update阶段:
- unsafe_componentWillReceiveProps
- 该方法已被弃用,因为也是违背了生命周期中的异步渲染问题
- 当getDirvedStateFromProps存在时将componentWillReceiveProps将不会被执行
- getDerivedStateFromProps
- 上面写过
- shouldComponentUpdate
- 该方法是通过返回true和false实现判断是否
- 此方法是在渲染之前的最后一道关卡, 这个函数中可以对比props和state的值然后判断是否需要更新
- unsafe_componentWillUpdate 这个方法已经被弃用
- getSnapshotBeforeUpdate
该方法在已经准备渲染,都准备好了,但是dom渲染之前被调用,getSnapshotBeforeUpdate的返回值会作为componentDIdUpdate的第三个参数 - componenttDidUpdate 渲染完成之后被调用,避免在这里setState避免照成死循环
- componentWillUnmount 这里是被写在之前调用,这里别忘了将定时器给清除掉,不然会造成反复调用 重新渲染 函数组件:在任何情况下都会被重新渲染,使用memo优化 类组件:state发生改变时,props发生改变时 pureComponent:浅比较过程中确认有变更才会触发重新渲染 错误边界 是一种react组件 提供了两个方法
- getDerivedStateFormError 该方法用于捕获子组件的异常,然后将state中的hasEorror修改为true
- componentDidcatch当执行的时候,知道了错误,将错误日志提交到服务器
- 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会产生副作用
- 所有的事件都收拢到Action中去触发
- 所有的UI状态都交给Store去管理
- 所有的业务逻辑都交给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组件的应用状态,他分为四个部分,
- dispatch 2. store 3. action 4. view store存储上了数据层的所有数据当store发生变化时会引起数据层的更新,如果在view层调用acton就会让当前数据层发生更新从而实现数据变化 action会对所有的dispatch进行统一管理 flux是单向数据流,其优点是非常明确的数据流来源,不至于使逻辑混乱难以维护
第二个是redux redux是flux的简化设计版本,但是他吸收了flux的有点,也在flux的基础上进行了更改,比如flux可能有多个store,但是redux只能有一个store,他包含了三个内容
- reducer纯函数,用于描述状态的变化,返回完整的状态
- dispatch用于分发状态的变化
- 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使用的是分治的,比对通过三种方式
- 树比对:应为网页中一般很少有跨层级的移动dom方式,这里采用的是同层级的对比
- 组件比对:如果组件是同一类型就进行树比对,如果不是就放入补丁中
- 元素比对:通过对比元素的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层出现错误使整个应用崩溃,。 所以在处理异常我们使用两种方案
- 预防,引入空安全相关的方案,使用typescript预防,在3.7之后可以使用可选链操作符
- 兜底,使用兜底的高阶组件,封装成了内部的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的属性中使用箭头函数,或者每次都生成新的对象, 有三个解决方案:
- 通过useMemo,useCallback缓存函数来产生结果,避免生成新的对象
- 使用不可变数据,使用immutablejs和immerjs使数据不发生改变
- 手动控制,自己使用shouldComponentUpdate
十四、怎么增加代码的可维护性
可分析性:
- 目标:快速定位线上问题
- 预防:人工code Review,lint工具校验
- 兜底:sourcemap定位 可改变性:
- 目标:代码易于维护拓展
- 设计模式:组件设计模式
- 状态管理框架 稳定性:
- 目标:比秒修改代码硬气不必要的线上问题
- 核心业务覆盖单元测试 易测试性:
- 最好是使用函数式组件,类组件因为自己具有状态,而且状态容易发生改变,所以非常不容易维护 加强工具的使用
- TypeScript
- esLint 代码规范检查器
- styleLint css规范检查器
- commitlint 前端代码提交规范
- editorconfig
- prettier 代码自动排版
十四、为什么要使用hooks
- 类组件this指向很难获得,因为类在运行的时候会产生自己的实例,自己内部可以实现状态变化,于是很难维护
- 类组件在类的内部很难做到优化,
hooks使用限制
- 不要在循环、条件、嵌套函数中调用hook
- 不要在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事件机制分为以下四个阶段
-
绑定阶段
-
事件合成
-
收集事件
-
触发事件回调函数
-
在本dom节点上添加一个仓库 store store中保存事件的处理函数
-
在document上添加事件处理函数,函数为react的合成事件
-
在合成事件中,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中的值的话
- 需要actions中保存所有修改state的方法
- 通过dispatch分发action,然后传递到reducer中,通过reducer修改state的值,然后完整修改state
- 通过subscribe监听数据的变化,然后将组件重新渲染 redux工程化
- reducer为纯函数,保存初始状态,通过combineReducer完成对reducer的合并,
- action-types保存dispatch中key的名称,为唯一值,不重复
- actions文件中保存所有执行dispatch分发的函数 4, 使用react-redux中的provider传入store,
- 使用connect的mapState和mapActions两种方式完成传递props参数 redux原理
- 执行createStore的时候会创建一个空仓库state赋值为undefined,创建三个函数
- getState就是将state返回
- dispatch就是调用reducer
- subscribe用于执行当值发生改变时调用回调函数
- 执行dispatch,传入一个基本不可能action,dispatch调用reducer,传入state和action,由于state一开始为undefined,那么函数就使用默认值得方式,将默认值提取,返回出来,赋值给state,等下一次调用reducer的时候state就是有值的,于是,就不使用初始值了,dispatch执行完毕之后需要将所有subscribe中保存的回调函数拿出来执行一次
- 定义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中的异步问题
- redux-thunk需要在action中进行异步操作,操作完成之后执行dispatch
- 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),
};
};
- 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如何做服务端渲染
- 使用nextjs
- 监听端口号,当服务器接收到请求时,在当前的路由表里面查找数据,将数据作为props和context传入到组件中
- 调用react的renderToString,将组件渲染为html字符串,然后返回给客户端
- 客户端浏览器将html字符串渲染到页面上