11、react组件的划分业务组件技术组件?
-
根据组件的职责通常把组件分为UI组件和容器组件。 -
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。 -
两者通过 React-Redux
提供connect
方法联系起来
12、react旧版生命周期函数
初始化阶段
-
getDefaultProps
:获取实例的默认属性 -
getInitialState
:获取每个实例的初始化状态 -
componentWillMount
:组件即将被装载、渲染到页面上 -
render
:组件在这里生成虚拟的DOM
节点 -
componentDidMount
:组件真正在被装载之后
运行中状态
-
componentWillReceiveProps
:组件将要接收到属性的时候调用 -
shouldComponentUpdate
:组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render
调用,后面的函数不会被继续执行了) -
componentWillUpdate
:组件即将更新不能修改属性和状态 -
render
:组件重新描绘 -
componentDidUpdate
:组件已经更新
销毁阶段
-
componentWillUnmount
:组件即将销毁
新版生命周期
在新版本中,React 官方对生命周期有了新的 变动建议:
-
使用 getDerivedStateFromProps
替换componentWillMount;
-
使用 getSnapshotBeforeUpdate
替换componentWillUpdate;
-
避免使用 componentWillReceiveProps
;
其实该变动的原因,正是由于上述提到的
Fiber
。首先,从上面我们知道 React 可以分成reconciliation
与commit
两个阶段,对应的生命周期如下:
reconciliation
-
componentWillMount
-
componentWillReceiveProps
-
shouldComponentUpdate
-
componentWillUpdate
commit
-
componentDidMount
-
componentDidUpdate
-
componentWillUnmount
在
Fiber
中,reconciliation
阶段进行了任务分割,涉及到 暂停 和 重启,因此可能会导致reconciliation
中的生命周期函数在一次更新渲染循环中被 多次调用 的情况,产生一些意外错误
新版的建议生命周期如下:
class Component extends React.Component {
// 替换 `componentWillReceiveProps` ,
// 初始化和 update 时被调用
// 静态函数,无法使用 this
static getDerivedStateFromProps(nextProps, prevState) {}
// 判断是否需要更新组件
// 可以用于组件性能优化
shouldComponentUpdate(nextProps, nextState) {}
// 组件被挂载后触发
componentDidMount() {}
// 替换 componentWillUpdate
// 可以在更新之前获取最新 dom 数据
getSnapshotBeforeUpdate() {}
// 组件更新后调用
componentDidUpdate() {}
// 组件即将销毁
componentWillUnmount() {}
// 组件已销毁
componentDidUnMount() {}
}
使用建议:
-
在
constructor
初始化state
; -
在
componentDidMount
中进行事件监听,并在componentWillUnmount
中解绑事件; -
在
componentDidMount
中进行数据的请求,而不是在componentWillMount
; -
需要根据
props
更新
state
时,使用
getDerivedStateFromProps(nextProps, prevState)
;
-
旧 props 需要自己存储,以便比较;
public static getDerivedStateFromProps(nextProps, prevState) {
// 当新 props 中的 data 发生变化时,同步更新到 state 上
if (nextProps.data !== prevState.data) {
return {
data: nextProps.data
}
} else {
return null1
}
}
可以在componentDidUpdate监听 props 或者 state 的变化,例如:
componentDidUpdate(prevProps) {
// 当 id 发生变化时,重新获取数据
if (this.props.id !== prevProps.id) {
this.fetchData(this.props.id);
}
}
-
在componentDidUpdate使用setState时,必须加条件,否则将进入死循环; -
getSnapshotBeforeUpdate(prevProps, prevState)可以在更新之前获取最新的渲染数据,它的调用是在 render 之后, update 之前; -
shouldComponentUpdate: 默认每次调用setState,一定会最终走到 diff 阶段,但可以通过shouldComponentUpdate的生命钩子返回false来直接阻止后面的逻辑执行,通常是用于做条件渲染,优化渲染的性能。
13、react性能优化是哪个周期函数
shouldComponentUpdate
这个方法用来判断是否需要调用render方法重新描绘dom。因为dom的描绘非常消耗性能,如果我们能在shouldComponentUpdate方
法中能够写出更优化的dom diff
算法,可以极大的提高性能
14、为什么虚拟dom会提高性能
虚拟
dom
相当于在js
和真实dom
中间加了一个缓存,利用dom diff
算法避免了没有必要的dom
操作,从而提高性能
具体实现步骤如下
-
用 JavaScript
对象结构表示 DOM 树的结构;然后用这个树构建一个真正的DOM
树,插到文档当中 -
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异 -
把2所记录的差异应用到步骤1所构建的真正的 DOM
树上,视图就更新
15、diff算法?
-
把树形结构按照层级分解,只比较同级元素。 -
给列表结构的每个单元添加唯一的 key
属性,方便比较。 -
React
只会匹配相同class
的component
(这里面的class
指的是组件的名字) -
合并操作,调用 component
的setState
方法的时候,React
将其标记为 –dirty
.到每一个事件循环结束,React
检查所有标记dirty
的component
重新绘制. -
选择性子树渲染。开发人员可以重写 shouldComponentUpdate
提高diff
的性能
16、react性能优化方案
-
重写 shouldComponentUpdate
来避免不必要的dom操作 -
使用 production
版本的react.js
-
使用 key
来帮助React
识别列表中所有子组件的最小变化
17、简述flux 思想
Flux
的最大特点,就是数据的”单向流动”。
-
用户访问 View
-
View
发出用户的Action
-
Dispatcher
收到Action
,要求Store
进行相应的更新 -
Store
更新后,发出一个"change"
事件 -
View
收到"change"
事件后,更新页面
18、说说你用react有什么坑点?
1. JSX做表达式判断时候,需要强转为boolean类型
如果不使用
!!b
进行强转数据类型,会在页面里面输出0
。
render() {
const b = 0;
return <div>
{
!!b && <div>这是一段文本</div>
}
</div>
}
2. 尽量不要在 componentWillReviceProps
里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃
3. 给组件添加ref时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop处理,让ref属性接受到新函数的时候,react内部会先清空ref,也就是会以null为回调参数先执行一次ref这个props,然后在以该组件的实例执行一次ref,所以用匿名函数做ref的时候,有的时候去ref赋值后的属性会取到null
4. 遍历子节点的时候,不要用 index 作为组件的 key 进行传入
class Demo {
render() {
return <button onClick={(e) => {
alert('我点击了按钮')
}}>
按钮
</button>
}
}
你觉得你这样设置点击事件会有什么问题吗?
由于
onClick
使用的是匿名函数,所有每次重渲染的时候,会把该onClick
当做一个新的prop
来处理,会将内部缓存的onClick
事件进行重新赋值,所以相对直接使用函数来说,可能有一点的性能下降
修改
class Demo {
onClick = (e) => {
alert('我点击了按钮')
}
render() {
return <button onClick={this.onClick}>
按钮
</button>
}
20、react 的虚拟dom是怎么实现的
首先说说为什么要使用
Virturl DOM
,因为操作真实DOM
的耗费的性能代价太高,所以react
内部使用js
实现了一套dom结构,在每次操作在和真实dom之前,使用实现好的diff算法,对虚拟dom进行比较,递归找出有变化的dom节点,然后对其进行更新操作。为了实现虚拟DOM
,我们需要把每一种节点类型抽象成对象,每一种节点类型有自己的属性,也就是prop,每次进行diff
的时候,react
会先比较该节点类型,假如节点类型不一样,那么react
会直接删除该节点,然后直接创建新的节点插入到其中,假如节点类型一样,那么会比较prop
是否有更新,假如有prop
不一样,那么react
会判定该节点有更新,那么重渲染该节点,然后在对其子节点进行比较,一层一层往下,直到没有子节点
21、react 的渲染过程中,兄弟节点之间是怎么处理的?也就是key值不一样的时候
通常我们输出节点的时候都是map一个数组然后返回一个
ReactNode
,为了方便react
内部进行优化,我们必须给每一个reactNode
添加key
,这个key prop
在设计值处不是给开发者用的,而是给react用的,大概的作用就是给每一个reactNode
添加一个身份标识,方便react进行识别,在重渲染过程中,如果key一样,若组件属性有所变化,则react
只更新组件对应的属性;没有变化则不更新,如果key不一样,则react先销毁该组件,然后重新创建该组件
原文始发于微信公众号(消失的程序员):React.js面试题精选—2
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250875.html