React
2021-03-24 15:03:09 0 举报
AI智能生成
前端面试_React
作者其他创作
大纲/内容
React 使用
React 基本使用
JSX
变量、表达式
class、style
子元素和组件
class、style
子元素和组件
React 的 class 要写成 className
dangerouslySetInnerHTML 设置 innerHTML
<div dangerouslySetInnerHTML={{ __html: 'xxx' }} />
条件判断
- if else
- 三元表达式
- 逻辑运算符&& ||
渲染列表
map
key
key
key 与 Vue 的 key 类似,必填,且不能是 index 或 random
React 事件
bind this
React 事件为何 bind this?
普通方法中,this 指向 undefined,因此需要 .bind(this) 修改 this 指向
普通方法中,this 指向 undefined,因此需要 .bind(this) 修改 this 指向
可以在 constructor 中 bind(this) ,也可以在 render 中 bind(this);
推荐前者,只执行一次 bind,后者每触发一次事件都执行一次 bind(性能优化)
推荐前者,只执行一次 bind,后者每触发一次事件都执行一次 bind(性能优化)
静态方法中(箭头函数),this 指向当前实例,推荐使用(配置好Babel)
event 参数
React 事件和 DOM 事件的区别?
- event 不是原生 event (MouseEvent),而是 SyntheticEvent(封装的合成事件),模拟出了DOM事件所有能力
- 可以通过 event.nativeEvent 获取原生事件对象
- 所有的事件,都被挂载到 document 上(React17 绑定到 root 上)
- 和 DOM 事件不一样,和 Vue事件也不一样
传递自定义参数
最后追加一个参数,即可接收 event:clickHandler(id, title, event)
React 表单
受控组件
受控组件:表单值受 state 控制(将 value 设置成 state,通过 onChange 来 setState,实现双向数据绑定)
非受控组件:表单中的值不受 state 控制。
非受控组件:表单中的值不受 state 控制。
input、textarea、select 用 value
label 标签中的 for 在 JS 中是保留字,所以用 htmlFor 代替 for。
在 React 中 <textarea> 使用 value 属性(Vue 也是)
checkbox、radio 用 checked
React 父子组件通讯
props 传递数据
props 传递函数
props 类型检查(propTypes)
props 传递函数
props 类型检查(propTypes)
父组件可以给子组件传递数据,也可以传递函数;
在子组件中,通过 this.props 获取父组件传递的数据;
在子组件中,通过 this.props 获取父组件传递的数据;
状态提升:把状态(数据)提到最高级别的组件来管理,低层组件只负责渲染和提交数据。
setState
state 要在 constructor 构造函数中定义
不能直接修改 state 的值
- 通过 setState 去修改 state 的值
- 要用不可变值,否则直接修改 state 的值
不可变值
操作数组、对象的的常用形式
数组的 push、pop、splice 这些方法会改变原数组,不可用;
concat、slice、filter 、解构这些方法不会改变原数组,可用;
concat、slice、filter 、解构这些方法不会改变原数组,可用;
push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
arr.push(element1, ..., elementN)
arr.push(element1, ..., elementN)
pop() 方法从数组中删除最后一个元素,并返回该元素的值。
splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
slice() 方法什么参数都不传,就是直接复制数组,生成副本。
arr.slice([begin[, end]])
slice() 方法什么参数都不传,就是直接复制数组,生成副本。
arr.slice([begin[, end]])
filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
Object.assign() 、解构方式不会改变原对象,可用
SCU(shouldComponentUpdate)
setState 是同步还是异步
直接使用是异步的,拿不到最新值
可以在 setState 回调中拿到最新的值(Vue $nextTick)
setTimeout 和 自定义的 DOM 事件中 setState 是同步的
componentWillUnmount 中及时销毁自定义 DOM 事件、清除定时器
setState 可能会合并 state
传入对象,会被合并(类似于object.assign({ count: 1 }, { count: 1 }, { count: 1 }))
传入函数,不会被合并
React 组件生命周期
单个组件生命周期
生命周期图示(常用)
constructor
对应 Vue beforeCreated
render
render 生命周期在 Vue 中是没有的,因为 Vue 的模板是直接写在 template 里面的,没有一个函数专门去返回模板
componentDidMount
- 在组件第一次渲染后调用
- 在这里执行 ajax 请求
- 对应 Vue mounted
shouldComponentUpdate
- 返回一个布尔值
- 在组件接收到新的 props 或者 state 时被调用
- 在初始化时或者使用 forceUpdate 时不被调用
componentDidUpdate
- 在组件完成更新后立即调用;
- 在初始化时不会被调用;
- 对应 Vue updated
componentWillUnmount
- 在组件从 DOM 中移除之前立刻被调用
- 在这时销毁自定义 DOM 事件、清除定时器
- 对应 Vue beforeDestroyed
父子组件生命周期,和 Vue 一样
React 高级特性
函数组件
React 函数组件和 class 组件有何区别?
- 纯函数,输入props,输出JSX;
- 没有实例,没有生命周期,没有state;
- 不能扩展其它方法;
如果只输入 props,输出 JSX,就用函数组件;
如果用其他逻辑:设 state 或 对生命周期进行一些处理,就用 class 组件
如果用其他逻辑:设 state 或 对生命周期进行一些处理,就用 class 组件
非受控组件
使用场景
必须手动操作 DOM,setState 实现不了:
- 文件上传 <input type="file">
- 某些富文本编辑器,需要传入DOM元素
特点
- input 的 value 不受 state 控制,只是拿 state 的值设置 defaultValue 初始值
- 通过 ref 获取 DOM 节点,拿到 value 值
示例
ref
defaultValue defaultChecked
手动操作 DOM 元素
defaultValue defaultChecked
手动操作 DOM 元素
受控组件 vs 非受控组件
受控组件:输入的时候,会同步修改 state 中相应的值(表单实时输入)
非受控组件:直接获取 DOM 的值,state 的值不会跟输入后 DOM 的值同步(需要直接操作 DOM 时,文件上传、富文本编辑器)
非受控组件:直接获取 DOM 的值,state 的值不会跟输入后 DOM 的值同步(需要直接操作 DOM 时,文件上传、富文本编辑器)
优先使用受控组件,符合 React 设计原则(数据驱动视图);
必须操作 DOM 时,再使用非受控组件。
必须操作 DOM 时,再使用非受控组件。
Portals
组件默认会按照既定的层次嵌套渲染
如何让组件渲染到父组件以外?
如何让组件渲染到父组件以外?
使用场景
- 父组件 overflow: hidden,父组件设了 BFC,限制了子组件展示
- 父组件 z-index 太小
- fixed 需要放在 body 第一层
让组件渲染时逃离父组件,以应对 CSS 兼容性及布局问题
context
使用场景
大型项目中,公共信息(语言、主题)如何传递给每个组件?
- 用 props 太繁琐(组件层级较深时,props 层层传递,太繁琐)
- 用 redux 小题大做(语言、主题只设置一次,没必要用 redux,数据结构很复杂的用 redux)
示例
生产和管理
// 创建 Context,填入默认值(任何一个 js 变量)
const ThemeContext = React.createContext('light')
const ThemeContext = React.createContext('light')
最外层通过 .Provider 生产和管理数据(其子组件都可以消费数据)
消费
class 组件
定义静态属性 contextType,然后通过 this.context 获取当前的 context
函数式组件
使用 .Consumer 包裹一个函数,函数的参数为 createContext 传入的值
考点
- 应用场景
- 核心 API
异步组件
使用场景
组件比较大、路由需要懒加载时使用(性能优化)
示例
- 通过 import() 引入组件
- 通过 React.lazy 去封装
- 外面包 React.Suspense 去执行 fallback,传入加载中提示
性能优化
shouldComponentUpdate(简称SCU)
基本用法
SCU 默认返回 true
通过对比前后状态:返回 true 时 继续渲染,返回 false 时不渲染;
可以优化性能
可以优化性能
SCU 的核心问题在那里?
SCU 默认返回 true,即React 默认重新渲染子组件:
父组件有更新,会触发父组件的 render,那么其所有子组件会重新渲染
父组件有更新,会触发父组件的 render,那么其所有子组件会重新渲染
SCU 一定要每次都用吗?
不一定,需要的时候才优化
可先不用 SCU,有性能问题时再考虑使用
可先不用 SCU,有性能问题时再考虑使用
React 为何不实现 SCU 的判断,而是交给用户?
- 性能优化是需要时才优化
- 必须配合不可变值一起使用:即便 React 在 SCU 实现了深度比较,如果用户未遵守不可变值的写法,则出现 bug
- 慎用深度比较(一次递归到底),影响性能
PureComponent 和 React.memo
PureComponent,SCU 中实现了浅比较
memo,函数组件中的 PureComponent
浅比较已适用大部分情况(尽量不要做深度比较(耗费性能))
不可变值 Immutable.js
彻底拥抱不可变值(深拷贝性能差)
基于共享数据(不是深拷贝),速度好
有一定的学习迁移成本,按需使用
基于共享数据(不是深拷贝),速度好
有一定的学习迁移成本,按需使用
state 设计的数据结构不要太深
高阶组件 HOC
关于组件公共逻辑的抽离
- mixin,已被React弃用
- 高阶组件 HOC
- Render Props
基本用法
高阶组件是一种模式,通过一个函数接收一个组件作为参数,返回一个实现了公共逻辑的新组件
示例
透传所有 props
redux connect 是高阶组件
基本用法
connect 源码
Render Props
基本用法
示例
Mouse 组件只有公共能力,至于如何渲染 App 组件说了算
Render Props 核心思想
通过一个函数将 class 组件的 state 作为 props 传递给纯函数组件
HOC vs Render Props
HOC:模式简单,但会增加组件层级(相应的会增加透传成本,以及透传中覆盖的可能)
Render Props:代码简洁,学习成本较高
按需使用
Render Props:代码简洁,学习成本较高
按需使用
Redux
Redux 考点
- 基本概念
- 单项数据流(画单向数据流图,重点!)
- react-redux(redux 怎么连接 react,考点不多,但要知道)
- 异步 action(重点!)
- 中间件(考察频率不高,但要知道)
Redux 单向数据流
基本概念
store state
action
reducer
action
reducer
reducer,接收 action 返回新的 state(用不可变值)
createStore 创建一个 store
store.subscribe 订阅一个更新
store.dispatch 触发一个 action,reducer 接收后去修改 state,然后触发更新订阅
createStore 创建一个 store
store.subscribe 订阅一个更新
store.dispatch 触发一个 action,reducer 接收后去修改 state,然后触发更新订阅
单向数据流概述
dispatch(action)
reducer -> newState
subscribe 触发通知
reducer -> newState
subscribe 触发通知
redux 数据流图
单向数据流:
- view 点击,dispatch 一个 action
- reducer 根据 action 返回一个新的 state
- state 发生变化触发 view 更新
react-redux
<Provider>
- 通过 react-redux 引入 Provider,Provider 是一个 React 组件;
- createStore 创建一个 store,其中传入的是 reducer;
- 把 store 传入 Provider,这样里面所有的组件都有了 store 的能力
connect
mapStateToProps mapDispatchToProps
mapStateToProps mapDispatchToProps
在各个组件组件中想要消费 redux 的能力,需要把定义好的组件通过 connect 包裹一下,返回高阶组件;
connect 包裹后,已经将 dispatch 作为 props 传入组件
connect 包裹后,已经将 dispatch 作为 props 传入组件
如果需要传入更多的信息,如通过 mapStateToProps、mapDispatchToProps 传入自定义属性、事件,将作为 props 传入组件
Redux action 如何处理异步
异步 action
使用异步 action,需要在创建 store 时,引入中间件 redux-thunk
异步 action 常用中间件
redux-thunk
redux-promise
redux-saga
redux-promise
redux-saga
简述 Redux 中间件原理
redux 中间件是对 dispatch 做的一个改造
示例
redux 中间件 logger 实现
react-router
考点
- 面试考点不多
- 路由模式(hash、H5 history),同 vue-router
- 路由配置(动态路由、懒加载),同 vue-router
react-router 路由模式
- hash 模式(默认),如 http://abc.com/#/user/10
- H5 history 模式,如 http://abc.com/user/20
H5 history 需要server端支持,因此无特殊要求可选择 hash 模式
2C 的可以使用 H5 history
2B 的可以使用 hash
2B 的可以使用 hash
用法
HashRouter 对应 hash 模式
BrowserRouter 对应 H5 history 模式
BrowserRouter 对应 H5 history 模式
react-router 路由配置
动态路由
跳转路由
懒加载
React 相关面试题
React 组件如何通讯
- 父子组件通过 props
- context 顶层组件向子组件下发数据
- redux
- 自定义事件
JSX 本质是什么
context 是什么,有何用途
涉及到一些公共信息,如主题颜色、语言等怎样向所有的子组件派发
shouldComponentUpdate 的用途
为了性能优化
默认返回 true
阻止不必要的渲染
配合不可变值使用
默认返回 true
阻止不必要的渲染
配合不可变值使用
描述 redux 单向数据流
看图
setState 是同步还是异步
React 原理
函数式编程
- 一种编程范式,概念比较多
- 纯函数
- 不可变值
回顾 SUC 和 redux 代码
vdom 和 diff
vdom 和 diff 是实现 React 的核心技术
vdom
h 函数
vnode 数据结构
patch 函数
patch(elem, vnode)
patch(vnode, newVnode)
patch(vnode, newVnode)
Vue2.x Vue3.0 React 三者实现 vdom 细节都不相同,但核心概念和实现思路都一样
diff
只比较同一层级,不跨级比较
tag 不相同,则直接删掉重建,不再深度比较
tag 和 key 都相同,则认为是相同节点,不再深度比较
JSX 本质
JSX 即 React.createElement 函数 ,执行生成 vnode;
第一个参数可能是组件也可能是个 html 标签
第一个参数可能是组件也可能是个 html 标签
怎么区分是组件还是 html 标签:
- React 组件名,首字母大写
- html 标签,首字母小写
React 合成事件
现象
- event 不是原生 event (MouseEvent),而是 SyntheticEvent(封装的合成事件),模拟出了 DOM 事件所有能力
- 可以通过 event.nativeEvent 获取原生事件对象
- 所有的事件,都被挂载到 document 上(React17开始,不再绑定到 document 上)
- 和 DOM 事件不一样,和 Vue事件也不一样
流程图
为何要合成事件机制?
- 更好的兼容性和跨平台
- 挂载到 document 上,减少内存消耗,避免频繁解绑
- 方便事件的统一管理(如事务机制)
React16 绑定到 document 上
React17 事件绑定到 root 组件
React17 事件绑定到 root 组件
root 组件即初始化 React 时传入的 DOM 节点
绑定到 root 上有利于多个 React 版本并存,如微前端
React16 React17事件绑定对比图
setState 和 batchUpdate
setState 表现
- 有时异步(普通使用),有时异步(setTimeout、自定义的 DOM 事件)
- 有时合并(对象形式),有时不合并(函数形式)
setState 主流程
关键点在于:执行 setState 时是否处于 batch update 机制中:
处于 batch update,走异步更新;否则,走同步更新
处于 batch update,走异步更新;否则,走同步更新
普通使用:setState执行时,isBatchUpdates 为 true
setTimeout:setState 执行时,isBatchUpdates 为 false
自定义 DOM 事件:setState 执行时,isBatchUpdates 为 false
setState 是同步还是异步?
setState 无所谓同步异步
看是否能命中 batchUpdate 机制:判断 isBatchingUpdates
看是否能命中 batchUpdate 机制:判断 isBatchingUpdates
哪些能命中 batchUpdate 机制?
React 可以“管理”的入口:
- 生命周期
- React 中注册的事件
能不能命中看入口
哪些不能命中 batchUpdate 机制?
React “管不到”的入口:
- setTimeout setInterval 等;
- 自定义的 DOM 事件
React 事务机制
先执行一个开始的逻辑,再执行函数体,再执行结束的逻辑
组件渲染过程
组件渲染过程
- prosp state
- render() 生成 vnode
- patch(elem, vnode)
组件更新过程
- setState(newState) 生成 dirtyComponents(可能有子组件)
- render() 生成 newVnode
- patch(vnode, newVnode)
上述的 patch 分为两个阶段:
reconciliation 阶段 - 执行 diff 算法,纯 JS 计算
commit 阶段 - 将 diff 结果渲染 DOM
React-fiber 如何优化性能
考虑到的性能问题
- JS 是单线程,且和 DOM 渲染公用一个线程
- 当组件足够复杂,组件更新时计算和渲染都压力巨大
- 同时再有DOM 操作需求(动画、鼠标拖拽等),将卡顿
解决方案 fiber
- 将 reconciliation 阶段进行任务拆分(commit 无法拆分)
- DOM 需要渲染时暂停,空闲时恢复
- 如何判断 DOM 需要渲染:window.requestIdleCallback
前端路由
React 真题演练
组件之间如何通讯?
- 父子组件 props
- 自定义事件
- Redux
- Context
JSX 本质是什么?
JSX 即 createElement 函数,执行返回 vnode
Context 是什么,如何应用?
父组件,向其下所有子孙组件传递信息;
一些简单的公共信息,如主题、语言等
一些简单的公共信息,如主题、语言等
SCU 用途
性能优化
配合不可变值使用
Redux 单向数据流
看图
setState 场景题
setState 异步、合并,setTimeout 同步
什么是纯函数
返回一个新值,没有副作用(不会修改其他值)
重点:不可变值
React 组件生命周期
单个组件生命周期
父子组件生命周期
React 发起 ajax 应该放在哪个生命周期
componentDidMount(DOM 已经渲染完)
渲染列表,为何使用 key
- 必须用 key,且不能是 index 和 random
- diff 算法中,通过 tag 和 key 来判断是否 sameNode
- 减少渲染次数,提升性能
函数组件和 class 组件区别
纯函数:
- 输入 props,输出 JSX
- 没有实例,没有生命周期,没有 state
- 不能扩展其他方法
什么是受控组件?
表单的值,受 state 控制
需要自行监听 onChange 事件去更新 state
需要自行监听 onChange 事件去更新 state
何时使用异步组件?
- 加载大组件
- 路由懒加载
多个组件有公共逻辑,如何抽离?
高阶组件(HOC)
Render Props
Render Props
Redux 如何进行异步请求
使用异步 action,如 redux-thunk
React-Router 如何配置懒加载
PureComponent 有何区别
实现了浅比较的 shouldCompoentUpdate(性能优化,配合不可变值)
React 事件和 DOM 事件的区别
- 所有事件挂载到 document 上
- event 不是原生事件,是 SyntheticEvent 合成事件
- dispatchEvent 机制
React 性能优化
- 渲染列表时加 key
- 自定义事件、DOM 事件及时销毁
- 合理使用异步组件
- 减少函数 bind(this) 次数
- 合理使用 SCU PureComponent memo
- 合理使用 Immutable.js
- webpack 层面的优化
- 前端通用的性能优化,如图片懒加载
- 使用 SSR
React 和 Vue 的区别
共同点
- 都支持组件化
- 都是数据驱动视图
- 都使用 vdom 操作 DOM
区别
- React 使用 JSX 拥抱 JS,Vue 使用模板拥抱 HTML
- React 是函数式编程,Vue 是声明式编程
- React 更多需要自力更生,Vue 把想要的都给你
React-Hooks
关于 React-Hooks
- 可选功能(class 或 Hooks)
- 100%向后兼容,没有破坏性改动
- 不会取代 class 组件
背景
React 函数组件
- 没有实例
- 没有生命周期
- 没有 state 和 setState,只能接收 props
class 组件的问题
- 大型组件很难拆分和重构
- 相同业务逻辑分散到各个方法中,逻辑混乱
- 复用逻辑复杂,如 HOC、Render Props
React 组件更易用函数来表达
- React 提倡函数式编程:view = fn(props)
- 函数更灵活、更易拆分,更易测试
- 但函数组件太简单,需要增强——Hooks
函数组件更适合 React 组件,但需要 Hooks 增强功能:
- useState 实现 state 和 setState
- useEffect 可模拟主要的生命周期
State Hook
让函数组件实现 state 和 setState
- 默认函数组件没有 state
- 函数组件是一个纯函数,执行完即销毁,无法存储 state
- 使用 State Hook 把 state 功能“钩”到纯函数中
useState 使用
const [state, setState] = useState(0);
- 通过 useState(0) 传入初始值,返回 [state, setState];
- 通过 state 获取值;
- 通过 setState 修改值
Effect Hook
让函数组件模拟生命周期
- 默认函数组件没有生命周期
- 函数组件是一个纯函数,执行完即销毁,自己无法实现生命周期
- 使用 Effect Hook 把生命周期“钩”到纯函数中
useEffect
模拟 componentDidMount + componentDidUpdate - useEffect 无依赖
模拟 componentDidMount - useEffect 依赖 []
模拟 componentDidUpdate - useEffect 依赖 [a, b]
模拟 componentWillUnmount - useEffect 中返回一个函数
useEffect 模拟 componentWillUnmout 注意事项
useEffect 中返回的函数 fn:
- useEffect 依赖 [],组件销毁时执行 fn,等于 componentWillUnmount
- 组件无依赖或依赖 [a, b],组件更新时执行 fn,即下一次更新前都会执行 fn,无论更新或卸载
其他 Hooks
useRef
获取 DOM 节点
useContext
涉及到一些公共信息,如主题颜色、语言等向所有的子组件派发
useReducer
useReducer 和 Redux 的区别
- userReducer 是 useState 的代替方案,用于 state 复杂变化
- useReducer 是单个组件状态管理,组件通讯还需要 props
- Redux 是全局的状态管理,多组件共享数据
useReducer 能代替 Redux 吗
useReducer 借鉴 Redux,应用场景不一样,不能取代 Redux
useMemo
缓存数据
React 默认会更新所有子组件
class 组件使用 SCU 和 PureComponent 做优化
Hooks 使用 useMemo 做优化,但优化原理是相同的:都是通过对 props 的浅层对比实现优化
class 组件使用 SCU 和 PureComponent 做优化
Hooks 使用 useMemo 做优化,但优化原理是相同的:都是通过对 props 的浅层对比实现优化
useCallback
缓存函数
React Hooks 常见的优化策略:useMemo、useCallback
自定义 Hook
- 封装通用的功能
- 开发和使用第三方 Hooks
- 自定义 Hook 带了无限的扩展性,解耦代码
- 本质上是函数,要以 use 开头
- 内部正常使用 useState useEffect 或其他 Hooks
- 自定义返回结果,格式不限
第三方 Hooks
Collection of React Hooks
alibaba-hooks
组件逻辑复用
class 组件逻辑复用
高阶组件 HOC
- 组件层级嵌套过多,不易渲染,不易调试
- HOC会劫持props,必须严格规范,容易出现疏漏
Render Props
- 学习成不高,不易理解
- 只能传递纯函数,而默认情况下纯函数功能有限
用 Hooks 组件逻辑复用的好处
- 完全符合 Hooks 原有规则,没有其他要求,易理解记忆
- 变量作用域和明确
- 不会产生组件嵌套
规范和注意事项
React Hooks 命名规范
所有 Hooks 都以 use 开头,如 useXxx;
自定义 Hooks 也要以 use 开头
非 Hooks,尽量不要用 useXxx 的写法
自定义 Hooks 也要以 use 开头
非 Hooks,尽量不要用 useXxx 的写法
React Hooks 使用规范
只能用于 React 函数组件和自定义 Hooks 中
Hooks 本身就是为函数组件设计的
只能用于顶层代码,不能在循环、判断中使用 Hooks
- 无论是 render 还是 re-render,Hooks 调用顺序必须一致
- 如果 Hooks 出现在循环、判断里,则无法保证顺序一致
- Hooks 严重依赖于调用顺序
ESLint 插件:eslint-plugin-react-hooks
React Hooks 注意事项
useState 初始化值,只执行一次,更新时不会再执行
useEffect 依赖为[](即模拟DidMount)时,内部不能修改 state
解决方法:
- 引入自定义变量,操作自定义变量---打破了纯函数的规则不推荐
- 使用 useRef(0),操作 countRef.current ---看似打破了纯函数规则,但是在 Hooks 规则之内使用没有问题
useEffect 的依赖中有对象或数组时,可能会出现死循环
useEffect 中通过 Object.is() 去判断是否更新
Object.is({}, {}) // false
Object.is([], []) // false
Object.is({}, {}) // false
Object.is([], []) // false
相关面试题
为什么用 React Hooks,它解决了什么问题?
为什么用 React Hooks
- 完善函数组件的能力,函数更适合 React 组件
- 组件逻辑复用,Hooks 表现更好
- class 复杂组件正在变的费解,不易拆解,不易测试,逻辑混乱
React Hooks 解决了什么问题
class 组件中相同的逻辑散落各处:
- DidMount 和 DidUpdate 中获取数据
- DidMount 绑定事件,WillUnmount 解绑事件
使用 Hooks,相同逻辑分割到一个 useEffect 中
React Hooks 如何模拟生命周期?
- 模拟 componentDidMount:useEffect 依赖[]
- 模拟 componentDidUpdate:useEffect 无依赖或依赖[a, b]
- 模拟 componentWillUnmount:useEffect 中返回一个函数
useEffect 返回 fn
- useEffect 依赖[],组件销毁时执行 fn,相当于 componentWillUnmount
- useEffect 无依赖或依赖[a, b],组件更新时执行 fn
- 即,下一次执行 useEffect 前,都会执行 fn,无论卸载或更新
如何自定义 Hook?
定义 state -> 设置 state -> 返回数据
React Hooks 性能优化
- useMemo 缓存数据
- useCallback 缓存函数
React Hooks 有哪些坑?
- useState 初始化值,只初始化一次
- useEffect 内部不能修改 state
- useEffect 可能出现死循环
Hook 相比 HOC 和 Render Props 有哪些优点?
- 完全符合 Hooks 原有规则
- 变量和作用域明确
- 不会产生组件嵌套
0 条评论
下一页