西安企业网站制作价格,建设网站时怎么用外部字体,免费做电子章网站,响应式网站展示型面试题 129. React.forwardRef是什么#xff1f;它有什么作用#xff1f;
参考回答#xff1a;
React.forwardRef 会创建一个React组件#xff0c;这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见#xff0c;但在以下两种场景中特别有…面试题 129. React.forwardRef是什么它有什么作用
参考回答
React.forwardRef 会创建一个React组件这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见但在以下两种场景中特别有用
1 转发 refs 到 DOM 组件
2 在高阶组件中转发 refs面试题 130. 简述React的状态提升是什么使用场景有哪些
参考回答
React的状态提升就是用户对子组件操作子组件不改变自己的状态通过自己的props把这个操作改变的数据传递给父组件改变父组件的状态从而改变受父组件控制的所有子组件的状态这也是React单项数据流的特性决定的。官方的原话是共享 state(状态) 是通过将其移动到需要它的组件的最接近的共同祖先组件来实现的。 这被称为“状态提升(Lifting State Up)”。概括来说就是将多个组件需要共享的状态提升到它们最近的父组件上在父组件上改变这个状态然后通过props分发给子组件。一个简单的例子父组件中有两个input子组件如果想在第一个输入框输入数据来改变第二个输入框的值这就需要用到状态提升。class Father extends React.Component {
constructor(props) {
super(props)
this.state {
Value1: ,
Value2:
}
}
value1Change(aa) {
this.setState({
Value1: aa
})
}
value2Change(bb) {
this.setState({
Value2: bb
})
}
render() {
return ()
}
}
class Child1 extends React.Component {
constructor(props) {
super(props)
}
changeValue(e) {
this.props.onvalue1Change(e.target.value)
}
render() {
return (
{this.props.Value1})
}
}
class Child2 extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
{this.props.value2})
}
}ReactDOM.render(
,
document.getElementById(root)
)面试题 131. React 中的高阶组件运用了什么设计模式
参考回答
使用了装饰模式高阶组件的运用
function withWindowWidth(BaseComponent) {
class DerivedClass extends React.Component {
state {
windowWidth: window.innerWidth,
}
onResize () {
this.setState({
windowWidth: window.innerWidth,
})
}
componentDidMount() {
window.addEventListener(resize, this.onResize)
}
componentWillUnmount() {
window.removeEventListener(resize, this.onResize);
}
render() {
return
}
}
return DerivedClass;
}
const MyComponent (props) {
returnWindow width is: {props.windowWidth}};
export default withWindowWidth(MyComponent);装饰模式的特点是不需要改变 被装饰对象 本身而只是在外面套一个外壳接口。JavaScript 目前已经有了原生装饰器的提案其用法如下testable
class MyTestableClass {
}面试题 132. React中constructor和getInitialState的区别?
参考回答
两者都是用来初始化state的。前者是ES6中的语法后者是ES5中的语法新版本的React中已经废弃了该方法。getInitialState是ES5中的方法如果使用createClass方法创建一个Component组件可以自动调用它的getInitialState方法来获取初始化的State对象var APP React.creatClass ({
getInitialState() {
return {
userName: hi,
userId: 0
};}
})React在ES6的实现中去掉了getInitialState这个hook函数规定state在constructor中实现如下Class App extends React.Component{
constructor(props){
super(props);
this.state{};
}
}面试题 133. React 如何实现强制刷新
参考回答
component.forceUpdate() 一个不常用的生命周期方法, 它的作用就是强制刷新官网解释如下默认情况下当组件的 state 或 props 发生变化时组件将重新渲染。如果 render() 方法依赖于其他数据则可以调用 forceUpdate() 强制让组件重新渲染。
调用 forceUpdate() 将致使组件调用 render() 方法此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法包括 shouldComponentUpdate() 方法。如果标记发生变化React 仍将只更新 DOM。
通常你应该避免使用 forceUpdate()尽量在 render() 中使用 this.props 和 this.state。
shouldComponentUpdate 在初始化 和 forceUpdate 不会执行面试题 134. 简述React 之 高低版本区别
参考回答
1、引入文件不同
高版本react.production.js、 react-dom.production.min.js、browser.min.js
低版本react.min.js、react-dom.min.js、browser.min.js
2、创建组件方式不同
高版本通过 类 的继承—class xx extends React.Component {
}
低版本React.createClass {
}
3、生命周期所用钩子函数不同
高版本3个componentWillMount、render、componentDidMount
低版本5个getDefaultProps、getInitialState、componentWillMount、render、componentDidMount
4、属性之间传值
高版本用组件defaultProps构造器传值
低版本用钩子函数getDefaultProps传值
5、状态state不同
高版本在constructor中–用this.state {
}
初始状态调用this.setState()需要在constructor中通过bind绑定this指向
低版本用getInitialState()初始状态用this.setState()更新组件的状态并在其内bind绑定this指向面试题 135. React setState 笔试题下面的代码输出什么
参考回答
class Example extends React.Component {
constructor() {
super()
this.state {
val: 0
}
}
componentDidMount() {
this.setState({ val: this.state.val 1 })
console.log(this.state.val)
// 第 1 次 log
this.setState({ val: this.state.val 1 })
console.log(this.state.val)
// 第 2 次 log
setTimeout(() {
this.setState({ val: this.state.val 1 })
console.log(this.state.val)
// 第 3 次 log
this.setState({ val: this.state.val 1 })
console.log(this.state.val)
// 第 4 次 log
}, 0)
}
render() {
return null
}
}面试题 136. 简述React触发多次setstate那么render会执⾏⼏次
参考回答
多次setState会合并为⼀次render因为setState并不会⽴即改变state的值⽽是将其放到⼀个任务队列⾥最终将多个setState合并⼀次性更新⻚⾯。所以我们可以在代码⾥多次调⽤setState每次只需要关注当前修改的字段即可面试题 137. 简述原⽣事件和React事件的区别
参考回答
React 事件使⽤驼峰命名⽽不是全部⼩写。
通过 JSX , 你传递⼀个函数作为事件处理程序⽽不是⼀个字符串。
在 React 中你不能通过返回 false 来阻⽌默认⾏为。必须明确调⽤ preventDefault 。面试题 138. React ⾼阶组件、Render props、hooks 有什么区别为什么要 不断迭代
参考回答
这三者是⽬前react解决代码复⽤的主要⽅式
⾼阶组件HOC是 React 中⽤于复⽤组件逻辑的⼀种⾼级技巧。HOC ⾃身不是 React API 的
⼀部分它是⼀种基于 React 的组合特性⽽形成的设计模式。具体⽽⾔⾼阶组件是参数为组件
返回值为新组件的函数。
render props是指⼀种在 React 组件之间使⽤⼀个值为函数的 prop 共享代码的简单技术更
具体的说render prop 是⼀个⽤于告知组件需要渲染什么内容的函数 prop。
通常render props 和⾼阶组件只渲染⼀个⼦节点。让 Hook 来服务这个使⽤场景更加简单。这
两种模式仍有⽤武之地例如⼀个虚拟滚动条组件或许会有⼀个 renderltem 属性或是⼀个
可⻅的容器组件或许会有它⾃⼰的 DOM 结构。但在⼤部分场景下Hook ⾜够了并且能够帮助
减少嵌套。
1HOC 官⽅解释∶
⾼阶组件HOC是 React 中⽤于复⽤组件逻辑的⼀种⾼级技巧。HOC ⾃身不是 React API
的⼀部分它是⼀种基于 React 的组合特性⽽形成的设计模式。
简⾔之HOC是⼀种组件的设计模式HOC接受⼀个组件和额外的参数如果需要返回⼀个新的组
件。HOC 是纯函数没有副作⽤。
HOC的优缺点∶
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state {
data: selectData(DataSource, props)
};
}
// ⼀些通⽤的逻辑处理
render() {
// ... 并使⽤新数据渲染被包装的组件!
return ;
}
};
// 使⽤
const BlogPostWithSubscription withSubscription(BlogPost,
(DataSource, props) DataSource.getBlogPost(props.id));
复制代码
优点∶ 逻辑服⽤、不影响被包裹组件的内部逻辑。
缺点∶ hoc传递给被包裹组件的props容易和被包裹后的组件重名进⽽被覆盖
2Render props 官⽅解释∶
render prop是指⼀种在 React 组件之间使⽤⼀个值为函数的 prop 共享代码的简单技术
具有render prop 的组件接受⼀个返回React元素的函数将render的渲染逻辑注⼊到组件内部。在
这⾥render的命名可以是任何其他有效的标识符。
由此可以看到render props的优缺点也很明显∶
优点数据共享、代码复⽤将组件内的state作为props传递给调⽤者将渲染逻辑交给调⽤者。
缺点⽆法在 return 语句外访问数据、嵌套写法不够优雅
3Hooks 官⽅解释∶
// DataProvider组件内部的渲染逻辑如下
class DataProvider extends React.Components {
state {
name: Tom
}
render() {
return (共享数据组件⾃⼰内部的渲染逻辑{ this.props.render(this.state) });
}
}
// 调⽤⽅式
(
Hello {data.name})}/
复制代码
Hook是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使⽤ state 以及其
他的 React 特性。通过⾃定义hook可以复⽤代码逻辑。
以上可以看出hook解决了hoc的prop覆盖的问题同时使⽤的⽅式解决了render props的嵌套地狱
的问题。hook的优点如下∶
使⽤直观
解决hoc的prop 重名问题
解决render props 因共享数据 ⽽出现嵌套地狱的问题
能在return之外使⽤数据的问题。
需要注意的是hook只能在组件顶层使⽤不可在分⽀语句中使⽤。
总结∶∶ Hoc、render props和hook都是为了解决代码复⽤的问题但是hoc和render props都有特
定的使⽤场景和明显的缺点。hook是react16.8更新的新的API让组件逻辑复⽤更简洁明了同时也
解决了hoc和render props的⼀些缺点面试题 139. 对React-Fiber的理解它解决了什么问题
参考回答
React V15 在渲染时会递归⽐对 VirtualDOM 树找出需要变动的节点然后同步更新它们 ⼀
⽓呵成。这个过程期间 React 会占据浏览器资源这会导致⽤户触发的事件得不到响应并且会导致
掉帧导致⽤户感觉到卡顿。
// ⾃定义⼀个获取订阅数据的hook
function useSubscription() {
const data DataSource.getComments();
return [data];
}
//
function CommentList(props) {
const {data} props;
const [subData] useSubscription();
...
}
// 使⽤复制代码
为了给⽤户制造⼀种应⽤很快的“假象”不能让⼀个任务⻓期霸占着资源。 可以将浏览器的渲染、布
局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执⾏视作操作系统的“进程”需要通过某些调
度策略合理地分配 CPU 资源从⽽提⾼浏览器的⽤户响应速率, 同时兼顾任务执⾏效率。
所以 React 通过Fiber 架构让这个执⾏过程变成可被中断。“适时”地让出 CPU 执⾏权除了可以
让浏览器及时地响应⽤户的交互还有其他好处:
分批延时对DOM进⾏操作避免⼀次性操作⼤量 DOM 节点可以得到更好的⽤户体验
给浏览器⼀点喘息的机会它会对代码进⾏编译优化JIT及进⾏热代码优化或者对 reflow
进⾏修正。
核⼼思想: Fiber 也称协程或者纤程。它和线程并不⼀样协程本身是没有并发或者并⾏能⼒的需要
配合线程它只是⼀种控制流程的让出机制。让出 CPU 的执⾏权让 CPU 能在这段时间执⾏其他的
操作。渲染的过程可以被中断可以将控制权交回浏览器让位给⾼优先级的任务浏览器空闲后再恢复
渲染面试题 140. 简述对componentWillReceiveProps 的理解
参考回答
该⽅法当props发⽣变化时执⾏初始化render时不执⾏在这个回调函数⾥⾯你可以根据属性的变化通过调⽤this.setState()来更新你的组件状态旧的属性还是可以通过this.props来获取,这
⾥调⽤更新状态是安全的并不会触发额外的render调⽤。
使⽤好处 在这个⽣命周期中可以在⼦组件的render函数执⾏前获取新的props从⽽更新⼦组件⾃⼰的state。 可以将数据请求放在这⾥进⾏执⾏需要传的参数则从componentWillReceiveProps(nextProps)中获取。⽽不必将所有的请求都放在⽗组件中。于是该请求只会在该组件渲染时才会发出从⽽减轻请求负担。
componentWillReceiveProps在初始化render的时候不会执⾏它会在Component接受到新的状态(Props)时被触发⼀般⽤于⽗组件状态更新时⼦组件的重新渲染。面试题 141. 哪些⽅法会触发 React 重新渲染重新渲染 render 会做些什么
参考回答
1哪些⽅法会触发 react 重新渲染?
setState⽅法被调⽤
setState 是 React 中最常⽤的命令通常情况下执⾏ setState 会触发 render。但是这⾥有
个点值得关注执⾏ setState 的时候不⼀定会重新渲染。当 setState 传⼊ null 时并不会触
发 render。
return /;
}
}
}
// pages/page-a.js
export default withFetching(fetching(science-fiction))(MovieList);
// pages/page-b.js
export default withFetching(fetching(action))(MovieList);
// pages/page-other.js
export default withFetching(fetching(some-other-type))(MovieList);
复制代码
class App extends React.Component {
⽗组件重新渲染
只要⽗组件重新渲染了即使传⼊⼦组件的 props 未发⽣变化那么⼦组件也会重新渲染进⽽触发
render
2重新渲染 render 会做些什么?
会对新旧 VNode 进⾏对⽐也就是我们所说的Diff算法。
对新旧两棵树进⾏⼀个深度优先遍历这样每⼀个节点都会⼀个标记在到深度遍历的时候每遍历
到⼀和个节点就把该节点和新的节点树进⾏对⽐如果有差异就放到⼀个对象⾥⾯
遍历差异对象根据差异的类型根据对应对规则更新VNode
React 的处理 render 的基本思维模式是每次⼀有变动就会去重新渲染整个应⽤。在 Virtual DOM
没有出现之前最简单的⽅法就是直接调⽤ innerHTML。Virtual DOM厉害的地⽅并不是说它⽐直接
操作 DOM 快⽽是说不管数据怎么变都会尽量以最⼩的代价去更新 DOM。React 将 render 函数
返回的虚拟 DOM 树与⽼的进⾏⽐较从⽽确定 DOM 要不要更新、怎么更新。当 DOM 树很⼤时遍历
state {
a: 1
};
render() {
console.log(render);
return ({this.state.a}onClick{() {
this.setState({ a: 1 }); // 这⾥并没有改变 a 的值
}}Click methis.setState(null)}setState null);
}
}
复制代码
两棵树进⾏各种⽐对还是相当耗性能的特别是在顶层 setState ⼀个微⼩的修改默认会去遍历整棵
树。尽管 React 使⽤⾼度优化的 Diff 算法但是这个过程仍然会损耗性能面试题 142. 简述为什么React并不推荐优先考虑使⽤Context
参考回答
Context⽬前还处于实验阶段可能会在后⾯的发⾏版本中有很⼤的变化事实上这种情况已经发⽣了所以为了避免给今后升级带来⼤的影响和麻烦不建议在app中使⽤context。
尽管不建议在app中使⽤context但是独有组件⽽⾔由于影响范围⼩于app如果可以做到⾼内聚不破坏组件树之间的依赖关系可以考虑使⽤context
对于组件之间的数据通信或者状态管理有效使⽤props或者state解决然后再考虑使⽤第三⽅的成熟库进⾏解决以上的⽅法都不是最佳的⽅案的时候在考虑context。
context的更新需要通过setState()触发但是这并不是很可靠的Context⽀持跨组件的访问但是如果中间的⼦组件通过⼀些⽅法不影响更新⽐如 shouldComponentUpdate() 返回false那么不能保证Context的更新⼀定可以使⽤Context的⼦组件因此Context的可靠性需要关注面试题 143. React中的setState批量更新的过程是什么
参考回答
调⽤ setState 时组件的 state 并不会⽴即改变 setState 只是把要修改的 state 放⼊⼀个队列 React 会优化真正的执⾏时机并出于性能原因会将 React 事件处理程序中的多次React 事件处理程序中的多次 setState 的状态修改合并成⼀次状态修改。 最终更新只产⽣⼀次组件及其⼦组件的重新渲染这对于⼤型应⽤程序中的性能提升⾄关重要面试题 144. 简述React中setState的第⼆个参数作⽤是什么
参考回答
setState 的第⼆个参数是⼀个可选的回调函数。这个回调函数将在组件重新渲染后执⾏。等价于在componentDidUpdate ⽣命周期内执⾏。通常建议使⽤ componentDidUpdate 来代替此⽅式。在这个回调函数中你可以拿到更新后 state 的值
this.setState({
key1: newState1,
key2: newState2,
...
}, callback) // 第⼆个参数是 state 更新完成后的回调函数面试题 145. 简述React中的setState和replaceState的区别是什么
参考回答
1setState() setState()⽤于设置状态对象其语法如下
nextState将要设置的新状态该状态会和当前的state合并
callback可选参数回调函数。该函数会在setState设置成功且组件重新渲染后调⽤。
合并nextState和当前state并重新渲染组件。setState是React事件处理函数中和请求回调函数中
触发UI更新的主要⽅法。
var ShowTitle React.createClass({
getDefaultProps:function(){
return{
title : React
}
},
render : function(){
return{this.props.title}}
});
复制代码
this.setState({
key1: newState1,
key2: newState2,
...
}, callback) // 第⼆个参数是 state 更新完成后的回调函数
复制代码
setState(object nextState[, function callback])
复制代码
2replaceState() replaceState()⽅法与setState()类似但是⽅法只会保留nextState中
状态原state不在nextState中的状态都会被删除。其语法如下
nextState将要设置的新状态该状态会替换当前的state。
callback可选参数回调函数。该函数会在replaceState设置成功且组件重新渲染后调⽤。
总结 setState 是修改其中的部分状态相当于 Object.assign只是覆盖不会减少原来的状
态。⽽replaceState 是完全替换原来的状态相当于赋值将原来的 state 替换为另⼀个对象如
果新状态属性减少那么 state 中就没有这个状态面试题 146. 简述React中的props为什么是只读的
参考回答
this.props是组件之间沟通的⼀个接⼝原则上来讲它只能从⽗组件流向⼦组件。React具有浓重的函数式编程的思想。
提到函数式编程就要提⼀个概念纯函数。它有⼏个特点
给定相同的输⼊总是返回相同的输出。
过程没有副作⽤。
不依赖外部状态。
this.props就是汲取了纯函数的思想。props的不可以变性就保证的相同的输⼊⻚⾯显示的内容是⼀样的并且不会产⽣副作⽤面试题 147. 在React中组件的props改变时更新组件的有哪些⽅法
参考回答
在⼀个组件传⼊的props更新时重新渲染该组件常⽤的⽅法是在componentWillReceiveProps中将新
的props更新到组件的state中这种state被成为派⽣状态Derived State从⽽实现重新渲
染。React 16.3中还引⼊了⼀个新的钩⼦函数getDerivedStateFromProps来专⻔实现这⼀需求。
1componentWillReceiveProps已废弃
在react的componentWillReceiveProps(nextProps)⽣命周期中可以在⼦组件的render函数执
⾏前通过this.props获取旧的属性通过nextProps获取新的props对⽐两次props是否相同从
⽽更新⼦组件⾃⼰的state。
这样的好处是可以将数据请求放在这⾥进⾏执⾏需要传的参数则从
componentWillReceiveProps(nextProps)中获取。⽽不必将所有的请求都放在⽗组件中。于是该请
求只会在该组件渲染时才会发出从⽽减轻请求负担。
2getDerivedStateFromProps16.3引⼊
这个⽣命周期函数是为了替代componentWillReceiveProps存在的所以在需要使
⽤componentWillReceiveProps时就可以考虑使⽤getDerivedStateFromProps来进⾏替代。
两者的参数是不相同的⽽getDerivedStateFromProps是⼀个静态函数也就是这个函数不能通过
this访问到class的属性也并不推荐直接访问属性。⽽是应该通过参数提供的nextProps以及
prevState来进⾏判断根据新传⼊的props来映射到state。
需要注意的是如果props传⼊的内容不需要影响到你的state那么就需要返回⼀个null这个返回值
是必须的所以尽量将其写到函数的末尾
12. React中怎么检验props验证props的⽬的是什么
React为我们提供了PropTypes以供验证使⽤。当我们向Props传⼊的数据⽆效向Props传⼊的数据类
型和验证的数据类型不符就会在控制台发出警告信息。它可以避免随着应⽤越来越复杂从⽽出现的问
题。并且它还可以让程序变得更易读。
static getDerivedStateFromProps(nextProps, prevState) {
const {type} nextProps;
// 当传⼊的type发⽣变化的时候更新state
if (type ! prevState.type) {
return {
type,
};
}
// 否则对于state不进⾏任何操作
return null;
}面试题 148. 简述React中怎么检验props验证props的⽬的是什么
参考回答
React为我们提供了PropTypes以供验证使⽤。当我们向Props传⼊的数据⽆效向Props传⼊的数据类型和验证的数据类型不符就会在控制台发出警告信息。它可以避免随着应⽤越来越复杂从⽽出现的问题。并且它还可以让程序变得更易读。
import PropTypes from prop-types;
class Greeting extends React.Component {
render() {
return (
Hello, {this.props.name});
}
}
Greeting.propTypes {
name: PropTypes.string
};
当然如果项⽬汇中使⽤了TypeScript那么就可以不⽤PropTypes来校验⽽使⽤TypeScript定义接⼝来校验props。面试题 149. 简述React 废弃了哪些⽣命周期为什么
参考回答
被废弃的三个函数都是在render之前因为fber的出现很可能因为⾼优先级任务的出现⽽打断现有任
务导致它们会被执⾏多次。另外的⼀个原因则是React想约束使⽤者好的框架能够让⼈不得已写出容
易维护和扩展的代码这⼀点⼜是从何谈起可以从新增加以及即将废弃的⽣命周期分析⼊⼿
1) componentWillMount
⾸先这个函数的功能完全可以使⽤componentDidMount和 constructor来代替异步获取的数据的情
况上⾯已经说明了⽽如果抛去异步获取数据其余的即是初始化⽽已这些功能都可以在
constructor中执⾏除此之外如果在 willMount 中订阅事件但在服务端这并不会执⾏
willUnMount事件也就是说服务端会导致内存泄漏所以componentWilIMount完全可以不使⽤但使
⽤者有时候难免因为各 种各样的情况在 componentWilMount中做⼀些操作那么React为了约束开发
者⼲脆就抛掉了这个API
2) componentWillReceiveProps
在⽼版本的 React 中如果组件⾃身的某个 state 跟其 props 密切相关的话⼀直都没有⼀种很
优雅的处理⽅式去更新 state⽽是需要在 componentWilReceiveProps 中判断前后两个 props
是否相同如果不同再将新的 props更新到相应的 state 上去。这样做⼀来会破坏 state 数据的单
⼀数据源导致组件状态变得不可预测另⼀⽅⾯也会增加组件的重绘次数。类似的业务需求也有很多
如⼀个可以横向滑动的列表当前⾼亮的 Tab 显然⾪属于列表⾃身的时根据传⼊的某个值直接定位
到某个 Tab。为了解决这些问题React引⼊了第⼀个新的⽣命周期
getDerivedStateFromProps。它有以下的优点∶
getDSFP是静态⽅法在这⾥不能使⽤this也就是⼀个纯函数开发者不能写出副作⽤的代码
开发者只能通过prevState⽽不是prevProps来做对⽐保证了state和props之间的简单关系以
及不需要处理第⼀次渲染时prevProps为空的情况
基于第⼀点将状态变化setState和昂贵操作tabChange区分开更加便于 render 和
commit 阶段操作或者说优化。
3) componentWillUpdate
与 componentWillReceiveProps 类似许多开发者也会在 componentWillUpdate 中根据
props 的变化去触发⼀些回调 。 但不论是 componentWilReceiveProps 还 是
componentWilUpdate都有可能在⼀次更新中被调⽤多次也就是说写在这⾥的回调函数也有可能会
被调⽤多次这显然是不可取的。与 componentDidMount 类 似 componentDidUpdate 也不存
在这样的问题⼀次更新中 componentDidUpdate 只会被调⽤⼀次所以将原先写在
componentWillUpdate 中 的 回 调 迁 移 ⾄ componentDidUpdate 就可以解决这个问题。
另外⼀种情况则是需要获取DOM元素状态但是由于在fber中render可打断可能在wilMount中获
取到的元素状态很可能与实际需要的不同这个通常可以使⽤第⼆个新增的⽣命函数的解决
getSnapshotBeforeUpdate(prevProps, prevState)
4) getSnapshotBeforeUpdate(prevProps, prevState)
返回的值作为componentDidUpdate的第三个参数。与willMount不同的是
getSnapshotBeforeUpdate会在最终确定的render执⾏之前执⾏也就是能保证其获取到的元素状态
与didUpdate中获取到的元素状态相同。官⽅参考代码
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我们是否在 list 中添加新的 items
// 捕获滚动位置以便我们稍后调整滚动位置。
if (prevProps.list.length this.props.list.length) {
const list this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我们 snapshot 有值说明我们刚刚添加了新的 items
// 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
//这⾥的 snapshot 是 getSnapshotBeforeUpdate 的返回值
if (snapshot ! null) {
const list this.listRef.current;
list.scrollTop list.scrollHeight - snapshot;
}
}
render() {
return (div ref{this.listRef}{/* ...contents... */}/div面试题 150. React 16.X 中 props 改变后在哪个⽣命周期中处理
参考回答
在getDerivedStateFromProps中进⾏处理。
这个⽣命周期函数是为了替代componentWillReceiveProps存在的所以在需要使
⽤componentWillReceiveProps时就可以考虑使⽤getDerivedStateFromProps来进⾏替代。
两者的参数是不相同的⽽getDerivedStateFromProps是⼀个静态函数也就是这个函数不能通过
this访问到class的属性也并不推荐直接访问属性。⽽是应该通过参数提供的nextProps以及
prevState来进⾏判断根据新传⼊的props来映射到state。
需要注意的是如果props传⼊的内容不需要影响到你的state那么就需要返回⼀个null这个返回值
是必须的所以尽量将其写到函数的末尾
static getDerivedStateFromProps(nextProps, prevState) {
const {type} nextProps;
// 当传⼊的type发⽣变化的时候更新state
if (type ! prevState.type) {
return {
type,
};
}
// 否则对于state不进⾏任何操作
return null;
}面试题 151. React 性能优化在哪个⽣命周期它优化的原理是什么
参考回答
react的⽗级组件的render函数重新渲染会引起⼦组件的render⽅法的重新渲染。但是有的时候⼦组件的接受⽗组件的数据没有变动。⼦组件render的执⾏会影响性能这时就可以使⽤shouldComponentUpdate来解决这个问题。
使⽤⽅法如下
shouldComponentUpdate(nexrProps) {
if (this.props.num nexrProps.num) {
return false
}
return true;
}shouldComponentUpdate提供了两个参数nextProps和nextState表示下⼀次props和⼀次state
的值当函数返回false时候render()⽅法不执⾏组件也就不会渲染返回true时组件照常重渲
染。此⽅法就是拿当前props中值和下⼀次props中的值进⾏对⽐数据相等时返回false反之返回
true。
需要注意在进⾏新旧对⽐的时候是浅对⽐也就是说如果⽐较的数据时引⽤数据类型只要数据的引
⽤的地址没变即使内容变了也会被判定为true。
⾯对这个问题可以使⽤如下⽅法进⾏解决
1使⽤setState改变数据之前先采⽤ES6中assgin
进⾏拷⻉但是assgin只深拷⻉的数据的第⼀层所以说不是最完美的解决办法
2使⽤JSON.parse(JSON.stringfy())进⾏深拷⻉但是遇到数据为undefined和函数时就会
错。
shouldComponentUpdate(nexrProps) {
if (this.props.num nexrProps.num) {
return false
}
return true;
}const o2 Object.assign({},this.state.obj)
o2.student.count 00000;
this.setState({
obj: o2,
})const o2 JSON.parse(JSON.stringify(this.state.obj))
o2.student.count 00000;
this.setState({
obj: o2,
})面试题 152. 简述state 和 props 触发更新的⽣命周期分别有什么区别
参考回答
state 更新流程 这个过程当中涉及的函数
1. shouldComponentUpdate: 当组件的 state 或 props 发⽣改变时都会⾸先触发这个⽣命周
期函数。它会接收两个参数nextProps, nextState——它们分别代表传⼊的新 props 和新的
state 值。拿到这两个值之后我们就可以通过⼀些对⽐逻辑来决定是否有 re-render重渲
染的必要了。如果该函数的返回值为 false则⽣命周期终⽌反之继续
注意此⽅法仅作为性能优化的⽅式⽽存在。不要企图依靠此⽅法来“阻⽌”渲染因为这可能会产
⽣ bug。应该考虑使⽤内置的 PureComponent 组件⽽不是⼿动编写
shouldComponentUpdate()
1. componentWillUpdate当组件的 state 或 props 发⽣改变时会在渲染之前调⽤
componentWillUpdate。componentWillUpdate 是 React16 废弃的三个⽣命周期之⼀。过
去我们可能希望能在这个阶段去收集⼀些必要的信息⽐如更新前的 DOM 信息等等现在我们
完全可以在 React16 的 getSnapshotBeforeUpdate 中去做这些事
2. componentDidUpdatecomponentDidUpdate() 会在UI更新后会被⽴即调⽤。它接收
prevProps上⼀次的 props 值作为⼊参也就是说在此处我们仍然可以进⾏ props 值对⽐
再次说明 componentWillUpdate 确实鸡肋哈props 更新流程:
相对于 state 更新props 更新后唯⼀的区别是增加了对 componentWillReceiveProps 的调
⽤。关于 componentWillReceiveProps需要知道这些事情
componentWillReceiveProps它在Component接受到新的 props 时被触发。
componentWillReceiveProps 会接收⼀个名为 nextProps 的参数对应新的 props 值。
该⽣命周期是 React16 废弃掉的三个⽣命周期之⼀。在它被废弃前可以⽤它来⽐较
this.props 和 nextProps 来重新setState。在 React16 中⽤⼀个类似的新⽣命周期
getDerivedStateFromProps 来代替它面试题 153. 简述React中发起⽹络请求应该在哪个⽣命周期中进⾏为什么
参考回答
对于异步请求最好放在componentDidMount中去操作对于同步的状态改变可以放在
componentWillMount中⼀般⽤的⽐较少。
如果认为在componentWillMount⾥发起请求能提早获得结果这种想法其实是错误的通常
componentWillMount⽐componentDidMount早不了多少微秒⽹络上任何⼀点延迟这⼀点差异都
可忽略不计。react的⽣命周期 constructor() - componentWillMount() - render() -
componentDidMount()
上⾯这些⽅法的调⽤是有次序的由上⽽下依次调⽤。
constructor被调⽤是在组件准备要挂载的最开始此时组件尚未挂载到⽹⻚上。
componentWillMount⽅法的调⽤在constructor之后在render之前在这⽅法⾥的代码调⽤
setState⽅法不会触发重新render所以它⼀般不会⽤来作加载数据之⽤。
componentDidMount⽅法中的代码是在组件已经完全挂载到⽹⻚上才会调⽤被执⾏所以可以保
证数据的加载。此外在这⽅法中调⽤setState⽅法会触发重新渲染。所以官⽅设计这个⽅法
就是⽤来加载外部数据⽤的或处理其他的副作⽤代码。与组件上的数据⽆关的加载也可以在
constructor⾥做但constructor是做组件state初绐化⼯作并不是做加载数据这⼯作的
constructor⾥也不能setState还有加载的时间太⻓或者出错⻚⾯就⽆法加载出来。所以有副
作⽤的代码都会集中在componentDidMount⽅法⾥。
总结
跟服务器端渲染同构有关系如果在componentWillMount⾥⾯获取数据fetch data会执
⾏两次⼀次在服务器端⼀次在客户端。在componentDidMount中可以解决这个问题
componentWillMount同样也会render两次。
在componentWillMount中fetch data数据⼀定在render后才能到达如果忘记了设置初始状
态⽤户体验不好。
react16.0以后componentWillMount可能会被执⾏多次。面试题 154. 简述⾮嵌套关系组件的通信⽅式
参考回答
即没有任何包含关系的组件包括兄弟组件以及不在同⼀个⽗级中的⾮兄弟组件。
可以使⽤⾃定义事件通信发布订阅模式
可以通过redux等进⾏全局状态管理
如果是兄弟组件通信可以找到这两个兄弟节点共同的⽗节点, 结合⽗⼦间通信⽅式进⾏通信面试题 155. 简述如何解决 props 层级过深的问题
参考回答
使⽤Context API提供⼀种组件之间的状态共享⽽不必通过显式组件树逐层传递props
使⽤Redux等状态库。面试题 156. 简述React-Router的实现原理是什么
参考回答
客户端路由实现的思想
基于 hash 的路由通过监听
事件感知 hash 的变化
改变 hash 可以直接通过 location.hashxxx
基于 H5 history 路由
改变 url 可以通过 history.pushState 和 resplaceState 等会将URL压⼊堆栈同
时能够应⽤ history.go() 等 API
监听 url 的变化可以通过⾃定义事件触发实现
react-router 实现的思想
基于 history 库来实现上述不同的客户端路由实现思想并且能够保存历史记录等磨平浏览器
差异上层⽆感知
通过维护的列表在每次 URL 发⽣变化的回收通过配置的 路由路径匹配到对应的
Component并且 render面试题 157. 简述React-Router怎么设置重定向
参考回答
使⽤组件实现路由的重定向当请求 /users/:id 被重定向去 /users/profile/:id
属性 from: string需要匹配的将要被重定向路径。
属性 to: string重定向的 URL 字符串
属性 to: object重定向的 location 对象
属性 push: bool若为真重定向操作将会把新地址加⼊到访问历史记录⾥⾯并且⽆法回退到
前⾯的⻚⾯。面试题 158. 简述 react-router ⾥的 Link 标签和 a 标签的区别
参考回答
从最终渲染的 DOM 来看这两者都是链接都是 标签区别是∶ 是react-router ⾥实现
路由跳转的链接⼀般配合 使⽤react-router接管了其默认的链接跳转⾏为区别于传统
的⻚⾯跳转 的“跳转”⾏为只会触发相匹配的 对应的⻚⾯内容更新⽽不会刷新整个
⻚⾯。
做了3件事情:
有onclick那就执⾏onclick
click的时候阻⽌a标签默认事件
根据跳转href(即是to)⽤history (web前端路由两种⽅式之⼀history hash)跳转此
// location { pathname: /react }React// React时只是链接变了并没有刷新⻚⾯⽽标签就是普通的超链接了⽤于从当前⻚⾯跳转到href指
向的另⼀ 个⻚⾯(⾮锚点情况)。
a标签默认事件禁掉之后做了什么才实现了跳转?
let domArr document.getElementsByTagName(a)
[...domArr].forEach(item{
item.addEventListener(click,function () {
location.href this.href
})
})面试题 159. 简述React-Router如何获取URL的参数和历史对象
参考回答
1获取URL的参数
get传值
路由配置还是普通的配置如admin传参⽅式如admin?id1111。通过
this.props.location.search获取url获取到⼀个字符串?id1111 可以⽤urlqs
querystring浏览器提供的api URLSearchParams对象或者⾃⼰封装的⽅法去解析出id的值。
动态路由传值
路由需要配置成动态路由如path/admin/:id传参⽅式如admin/111。通过
this.props.match.params.id 取得url中的动态路由id部分的值除此之外还可以通过
useParamsHooks来获取
通过query或state传值
传参⽅式如在Link组件的to属性中可以传递对
象{pathname:/admin,query:111,state:111};。通过this.props.location.state
或this.props.location.query来获取即可传递的参数可以是对象、数组等但是存在缺点就是只
要刷新⻚⾯参数就会丢失。
2获取历史对象
如果React 16.8 时可以使⽤ React Router中提供的Hooks
let domArr document.getElementsByTagName(a)
[...domArr].forEach(item{
item.addEventListener(click,function () {
location.href this.href
})
})
import { useHistory } from react-router-dom;
let history useHistory()
2.使⽤this.props.history获取历史对象
let history this.props.history;面试题 160. 简述React-Router 4怎样在路由变化时重新渲染同⼀个组件
参考回答
当路由变化时即组件的props发⽣了变化会调⽤componentWillReceiveProps等⽣命周期钩⼦。那需要做的只是 当路由改变时根据路由也去请求数据class NewsList extends Component {
componentDidMount () {
this.fetchData(this.props.location);
}fetchData(location) {
const type location.pathname.replace(/, ) || top
this.props.dispatch(fetchListData(type))
}
componentWillReceiveProps(nextProps) {
if (nextProps.location.pathname ! this.props.location.pathname) {
this.fetchData(nextProps.location);
}
}
render () {
...
}
}利⽤⽣命周期componentWillReceiveProps进⾏重新render的预处理操作