共计 8090 个字符,预计需要花费 21 分钟才能阅读完成。
说说 React 组件开发中对于作用域的常见问题。
在 EMAScript5 语法标准中,对于作用域的常见问题如下。
(1)在 map 等办法的回调函数中,要绑定作用域 this(通过 bind 办法)。
(2)父组件传递给子组件办法的作用域是父组件实例化对象,无奈扭转。
(3)组件事件回调函数办法的作用域是组件实例化对象(绑定父组件提供的办法就是父组件实例化对象),无奈扭转。
在 EMAScript6 语法标准中,对于作用域的常见问题如下。
(1)当应用箭头函数作为 map 等办法的回调函数时,箭头函数的作用域是以后组件的实例化对象(即箭头函数的作用域是定义时的作用域),毋庸绑定作用域。
(2)事件回调函数要绑定组件作用域。
(3)父组件传递办法要绑定父组件作用域。
总之,在 EMAScript6 语法标准中,组件办法的作用域是能够扭转的。
什么是 React Fiber?
Fiber 是 React 16 中新的协调引擎或从新实现外围算法。它的次要指标是反对虚构 DOM 的增量渲染。React Fiber 的指标是进步其在动画、布局、手势、暂停、停止或重用等方面的适用性,并为不同类型的更新调配优先级,以及新的并发原语。
React Fiber 的指标是加强其在动画、布局和手势等畛域的适用性。它的次要个性是增量渲染: 可能将渲染工作宰割成块,并将其扩散到多个帧中。
为什么浏览器无奈读取 JSX?
浏览器只能解决 JavaScript 对象,而不能读取惯例 JavaScript 对象中的 JSX。所以为了使浏览器可能读取 JSX,首先,须要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,而后再将其传给浏览器。
react 中 key 的作用
简略的说:key 是虚构 DOM 中的一种标识,在更新显示是 key 起到了极其重要的作用
简单的说:当状态中的数据产生扭转的时候,react 会依据【新数据】生成【新的虚构 DOM】,随后 react 进行【新虚构 DOM】和【旧的虚构 DOM】的 diff 比拟,而在这个比拟过程中 key 就是起到是要害中用
在调用 setState 之后产生了什么
-
状态合并,触发和谐:
setState 函数之后,会将传入的参数对象与以后的状态合并,而后登程调用过程
-
依据新的状态构建虚构 dom 树
通过和谐过程,react 会高效的依据新的状态构建虚构 DOM 树,筹备渲染整个 UI 页面
-
计算新老树节点差别,最小化渲染
得倒新的虚构 DOM 树后,会计算出新老树的节点差别,会依据差别对界面进行最小化渲染
-
按需更新
在差别话计算中,react 能够绝对精确的晓得哪些地位产生了扭转以及该如何扭转,这保障按需更新,而不是发表从新渲染
React 最新的⽣命周期是怎么的?
React 16 之后有三个⽣命周期被废除(但并未删除)
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
官⽅打算在 17 版本齐全删除这三个函数,只保留 UNSAVE_前缀的三个函数,⽬的是为了向下兼容,然而对于开发者⽽⾔应该尽量避免使⽤他们,⽽是使⽤新增的⽣命周期函数代替它们。
⽬前 React16.8+ 的⽣命周期分为三个阶段,别离是挂载阶段、更新阶段、卸载阶段。
挂载阶段:
- constructor:构造函数,最先被执⾏,咱们通常在构造函数⾥初始化 state 对象或者给⾃定义⽅法绑定 this;
- getDerivedStateFromProps:static getDerivedStateFromProps(nextProps, prevState),这是个动态⽅法,当咱们接管到新的属性想去批改咱们 state,能够使⽤ getDerivedStateFromProps
- render:render 函数是纯函数,只返回须要渲染的东⻄,不应该蕴含其它的业务逻辑,能够返回原⽣的 DOM、React 组件、Fragment、Portals、字符串和数字、Boolean 和 null 等内容;
- componentDidMount:组件装载之后调⽤,此时咱们能够获取到 DOM 节点并操作,⽐如对 canvas,svg 的操作,服务器申请,订阅都能够写在这个⾥⾯,然而记得在 componentWillUnmount 中勾销订阅;
更新阶段:
- getDerivedStateFromProps: 此⽅法在更新个挂载阶段都可能会调⽤;
- shouldComponentUpdate:shouldComponentUpdate(nextProps, nextState),有两个参数 nextProps 和 nextState,示意新的属性和变动之后的 state,返回⼀个布尔值,true 示意会触发从新渲染,false 示意不会触发从新渲染,默认返回 true,咱们通常利⽤此⽣命周期来优化 React 程序性能;
- render:更新阶段也会触发此⽣命周期;
- getSnapshotBeforeUpdate:getSnapshotBeforeUpdate(prevProps, prevState), 这个⽅法在 render 之后,componentDidUpdate 之前调⽤,有两个参数 prevProps 和 prevState,示意之前的属性和之前的 state,这个函数有⼀个返回值,会作为第三个参数传给 componentDidUpdate,如果你不想要返回值,能够返回 null,此⽣命周期必须与 componentDidUpdate 搭配使⽤;
- componentDidUpdate:componentDidUpdate(prevProps, prevState, snapshot),该⽅法在 getSnapshotBeforeUpdate ⽅法之后被调⽤,有三个参数 prevProps,prevState,snapshot,示意之前的 props,之前的 state,和 snapshot。第三个参数是 getSnapshotBeforeUpdate 返回的,如果触发某些回调函数时须要⽤到 DOM 元素的状态,则将对⽐或计算的过程迁徙⾄ getSnapshotBeforeUpdate,而后在 componentDidUpdate 中统⼀触发回调或更新状态。
卸载阶段:
-componentWillUnmount:当咱们的组件被卸载或者销毁了就会调⽤,咱们能够在这个函数⾥去革除⼀些定时器,勾销⽹络申请,清理⽆效的 DOM 元素等垃圾清理⼯作。
总结:
- componentWillMount:在渲染之前执行,用于根组件中的 App 级配置;
- componentDidMount:在第一次渲染之后执行,能够在这里做 AJAX 申请,DOM 的操作或状态更新以及设置事件监听器;
- componentWillReceiveProps:在初始化 render 的时候不会执行,它会在组件承受到新的状态 (Props) 时被触发,个别用于父组件状态更新时子组件的从新渲染
- shouldComponentUpdate:确定是否更新组件。默认状况下,它返回 true。如果确定在 state 或 props 更新后组件不须要在从新渲染,则能够返回 false,这是一个进步性能的办法;
- componentWillUpdate:在 shouldComponentUpdate 返回 true 确定要更新组件之前件之前执行;
- componentDidUpdate:它次要用于更新 DOM 以响应 props 或 state 更改;
- componentWillUnmount:它用于勾销任何的网络申请,或删除与组件关联的所有事件监听器。
参考 前端进阶面试题具体解答
什么是 JSX
jsx 是 javascriptML 的简写,是 react 应用的一种文件,它利用 JavaScript 的表现力和相似 HTML 的模板语法,这使得 HTML 文件非常容易了解。此文件能使利用十分牢靠,并可能进步其性能
jsx 的语法规定
- 定义虚构 DOM 的时候 不须要写引号
- 标签中要混入 js 表达式的时候须要用 {}
- 在 jsx 中写标签的类名的时候 用 className 代替 class
- 内联款式的时候,须要 style={{key:value}}
- 标签必须要闭合
-
标签首字母的约定
若为小写字母,则将 jsx 转换为 html 中同名元素,若 html 中无该标签明对应的同名元素 则报错
若为大写字母,react 就去渲染对应的组件,若没有定义组件 则报错
- 当依据数据遍历生成的标签,肯定要给标签设置独自的 key 否则会报错
在 ReactNative 中,如何解决 adb devices 找不到连贯设施的问题?
在应用 Genymotion 时,首先须要在 SDK 的 platform-tools 中退出环境变量,而后在 Genymotion 中单击 Setting,抉择 ADB 选项卡,单击 Use custom Android SDK tools,浏览本地 SDK 的地位,单击 OK 按钮就能够了。启动虛拟机后,在 cmd 中输出 adb devices 能够查看设施。
react 性能优化计划
- 重写
shouldComponentUpdate
来防止不必要的 dom 操作 - 应用
production
版本的react.js
- 应用
key
来帮忙React
辨认列表中所有子组件的最小变动
React 怎么做数据的检查和变动
Model
扭转之后(可能是调用了setState
),触发了virtual dom
的更新,再用diff
算法来把 virtual DOM
比拟real DOM
,看看是哪个dom
节点更新了,再渲染real dom
redux 与 mobx 的区别?
两者对⽐:
- redux 将数据保留在单⼀的 store 中,mobx 将数据保留在扩散的多个 store 中
- redux 使⽤ plain object 保留数据,须要⼿动解决变动后的操作;mobx 适⽤ observable 保留数据,数据变动后⾃动解决响应的操作
- redux 使⽤不可变状态,这意味着状态是只读的,不能间接去批改它,⽽是应该返回⼀个新的状态,同时使⽤纯函数;mobx 中的状态是可变的,能够间接对其进⾏批改
mobx 相对来说⽐较简略,在其中有很多的形象,mobx 更多的使⽤⾯向对象的编程思维;redux 会⽐较简单,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助⼀系列的中间件来解决异步和副作⽤
- mobx 中有更多的形象和封装,调试会⽐较艰难,同时后果也难以预测;⽽ redux 提供可能进⾏工夫回溯的开发⼯具,同时其纯函数以及更少的形象,让调试变得更加的容易
场景辨析:
- 基于以上区别,咱们能够简略得剖析⼀下两者的不同使⽤场景。
- mobx 更适宜数据不简单的应⽤:mobx 难以调试,很多状态⽆法回溯,⾯对复杂度⾼的应⽤时,往往⼒不从⼼。
- redux 适宜有回溯需要的应⽤:⽐如⼀个画板应⽤、⼀个表格应⽤,很多时候须要撤销、重做等操作,因为 redux 不可变的个性,人造⽀持这些操作。
- mobx 适宜短平快的项⽬:mobx 上⼿简略,样板代码少,能够很⼤水平上提⾼开发效率。
- 当然 mobx 和 redux 也并不⼀定是⾮此即彼的关系,你也能够在项⽬中⽤ redux 作为全局状态治理,⽤ mobx 作为组件部分状态管理器来⽤。
你对【繁多数据源】有什么了解
redux 应用 store 将程序的整个状态存储在同一个中央,因而所有组件的状态都存储在 Store 中,并且它们从 Store 自身接管更新。繁多状态树能够更容易地跟踪随工夫的变动,并调试或检查程序
在 Reducer 文件里,对于返回的后果,要留神哪些问题?
在 Reducer 文件里,对于返回的后果,必须要应用 Object.assign ()来复制一份新的 state,否则页面不会跟着数据刷新。
return Object.assign({}, state, {
type: action.type,
shouldNotPaint: true,
});
哪些办法会触发 React 从新渲染?从新渲染 render 会做些什么?
(1)哪些办法会触发 react 从新渲染?
- setState()办法被调用
setState 是 React 中最罕用的命令,通常状况下,执行 setState 会触发 render。然而这里有个点值得关注,执行 setState 的时候不肯定会从新渲染。当 setState 传入 null 时,并不会触发 render。
class App extends React.Component {
state = {a: 1};
render() {console.log("render");
return (
<React.Fragement>
<p>{this.state.a}</p>
<button
onClick={() => { this.setState({ a: 1}); // 这里并没有扭转 a 的值 }} > Click me </button>
<button onClick={() => this.setState(null)}>setState null</button>
<Child />
</React.Fragement>
);
}
}
- 父组件从新渲染
只有父组件从新渲染了,即便传入子组件的 props 未发生变化,那么子组件也会从新渲染,进而触发 render
(2)从新渲染 render 会做些什么?
- 会对新旧 VNode 进行比照,也就是咱们所说的 Diff 算法。
- 对新旧两棵树进行一个深度优先遍历,这样每一个节点都会一个标记,在到深度遍历的时候,每遍历到一和个节点,就把该节点和新的节点树进行比照,如果有差别就放到一个对象外面
- 遍历差别对象,依据差别的类型,依据对应对规定更新 VNode
React 的解决 render 的根本思维模式是每次一有变动就会去从新渲染整个利用。在 Virtual DOM 没有呈现之前,最简略的办法就是间接调用 innerHTML。Virtual DOM 厉害的中央并不是说它比间接操作 DOM 快,而是说不论数据怎么变,都会尽量以最小的代价去更新 DOM。React 将 render 函数返回的虚构 DOM 树与老的进行比拟,从而确定 DOM 要不要更新、怎么更新。当 DOM 树很大时,遍历两棵树进行各种比对还是相当耗性能的,特地是在顶层 setState 一个渺小的批改,默认会去遍历整棵树。只管 React 应用高度优化的 Diff 算法,然而这个过程依然会损耗性能.
redux 有什么毛病
- 一个组件所须要的数据,必须由父组件传过来,而不能像 flux 中间接从 store 取
- 当一个组件相干数据更新时,即便父组件不须要用到这个组件,父组件还是会从新 render,可能会有效率影响,或者须要写简单的
shouldComponentUpdate
进行判断
对 React-Fiber 的了解,它解决了什么问题?
React V15 在渲染时,会递归比对 VirtualDOM 树,找出须要变动的节点,而后同步更新它们,零打碎敲。这个过程期间,React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿。
为了给用户制作一种利用很快的“假象”,不能让一个工作长期霸占着资源。能够将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“过程”,须要通过某些调度策略正当地调配 CPU 资源,从而进步浏览器的用户响应速率, 同时兼顾工作执行效率。
所以 React 通过 Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了能够让浏览器及时地响应用户的交互,还有其余益处:
- 分批延时对 DOM 进行操作,防止一次性操作大量 DOM 节点,能够失去更好的用户体验;
- 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修改。
核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程自身是没有并发或者并行能力的(须要配合线程),它只是一种管制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其余的操作。渲染的过程能够被中断,能够将控制权交回浏览器,让位给高优先级的工作,浏览器闲暇后再复原渲染。
组件是什么?类是什么?类变编译成什么
- 组件指的是页面的一部分,实质就是一个类,最实质就是一个构造函数
- 类编译成构造函数
在 React 中如何防止不必要的 render?
React 基于虚构 DOM 和高效 Diff 算法的完满配合,实现了对 DOM 最小粒度的更新。大多数状况下,React 对 DOM 的渲染效率足以业务日常。但在个别简单业务场景下,性能问题仍然会困扰咱们。此时须要采取一些措施来晋升运行性能,其很重要的一个方向,就是防止不必要的渲染(Render)。这里提下优化的点:
- shouldComponentUpdate 和 PureComponent
在 React 类组件中,能够利用 shouldComponentUpdate 或者 PureComponent 来缩小因父组件更新而触发子组件的 render,从而达到目标。shouldComponentUpdate 来决定是否组件是否从新渲染,如果不心愿组件从新渲染,返回 false 即可。
- 利用高阶组件
在函数组件中,并没有 shouldComponentUpdate 这个生命周期,能够利用高阶组件,封装一个相似 PureComponet 的性能
- 应用 React.memo
React.memo 是 React 16.6 新的一个 API,用来缓存组件的渲染,防止不必要的更新,其实也是一个高阶组件,与 PureComponent 非常相似,但不同的是,React.memo 只能用于函数组件。
在 React 中组件的 props 扭转时更新组件的有哪些办法?
在一个组件传入的 props 更新时从新渲染该组件罕用的办法是在 componentWillReceiveProps
中将新的 props 更新到组件的 state 中(这种 state 被成为派生状态(Derived State)),从而实现从新渲染。React 16.3 中还引入了一个新的钩子函数 getDerivedStateFromProps
来专门实现这一需要。
(1)componentWillReceiveProps(已废除)
在 react 的 componentWillReceiveProps(nextProps)生命周期中,能够在子组件的 render 函数执行前,通过 this.props 获取旧的属性,通过 nextProps 获取新的 props,比照两次 props 是否雷同,从而更新子组件本人的 state。
这样的益处是,能够将数据申请放在这里进行执行,须要传的参数则从 componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。
(2)getDerivedStateFromProps(16.3 引入)
这个生命周期函数是为了代替 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;
}
什么是 state
- 在组件初始化的时候 通过 this.state 给组件设置一个初始化的 state,第一次 render 的时候会用 state 来渲染组件
- 通过 this.setState 办法来更新 state