在 React 中如何处理事件
为了解决跨浏览器的兼容性问题,SyntheticEvent
实例将被传递给你的事件处理函数,SyntheticEvent
是 React 跨浏览器的浏览器原生事件包装器,它还领有和浏览器原生事件雷同的接口,包含 stopPropagation()
和 preventDefault()
。
比拟乏味的是,React 实际上并不将事件附加到子节点自身。React 应用单个事件侦听器侦听顶层的所有事件。这对性能有益处,也意味着 React 在更新 DOM 时不须要跟踪事件监听器。
React 事件机制
<div onClick={this.handleClick.bind(this)}> 点我 </div>
React 并不是将 click 事件绑定到了 div 的实在 DOM 上,而是在 document 处监听了所有的事件,当事件产生并且冒泡到 document 处的时候,React 将事件内容封装并交由真正的处理函数运行。这样的形式不仅仅缩小了内存的耗费,还能在组件挂在销毁时对立订阅和移除事件。
除此之外,冒泡到 document 上的事件也不是原生的浏览器事件,而是由 react 本人实现的合成事件(SyntheticEvent)。因而如果不想要是事件冒泡的话应该调用 event.preventDefault()办法,而不是调用 event.stopProppagation()办法。JSX 上写的事件并没有绑定在对应的实在 DOM 上,而是通过事件代理的形式,将所有的事件都对立绑定在了 document
上。这样的形式不仅缩小了内存耗费,还能在组件挂载销毁时对立订阅和移除事件。
另外冒泡到 document
上的事件也不是原生浏览器事件,而是 React 本人实现的合成事件(SyntheticEvent)。因而咱们如果不想要事件冒泡的话,调用 event.stopPropagation
是有效的,而应该调用 event.preventDefault
。
实现合成事件的目标如下:
- 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
- 对于原生浏览器事件来说,浏览器会给监听器创立一个事件对象。如果你有很多的事件监听,那么就须要调配很多的事件对象,造成高额的内存调配问题。然而对于合成事件来说,有一个事件池专门来治理它们的创立和销毁,当事件须要被应用时,就会从池子中复用对象,事件回调完结后,就会销毁事件对象上的属性,从而便于下次复用事件对象。
怎么用 React.createElement 重写上面的代码
Question:
const element = (
<h1 className="greeting">
Hello, rdhub.cn!
</h1>
);
Answer:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, rdhub.cn!'
);
对 componentWillReceiveProps 的了解
该办法当 props
发生变化时执行,初始化 render
时不执行,在这个回调函数外面,你能够依据属性的变动,通过调用 this.setState()
来更新你的组件状态,旧的属性还是能够通过 this.props
来获取, 这里调用更新状态是平安的,并不会触发额定的 render
调用。
应用益处: 在这个生命周期中,能够在子组件的 render 函数执行前获取新的 props,从而更新子组件本人的 state。能够将数据申请放在这里进行执行,须要传的参数则从 componentWillReceiveProps(nextProps)中获取。而不用将所有的申请都放在父组件中。于是该申请只会在该组件渲染时才会收回,从而加重申请累赘。
componentWillReceiveProps 在初始化 render 的时候不会执行,它会在 Component 承受到新的状态 (Props) 时被触发,个别用于父组件状态更新时子组件的从新渲染。
React 的事件和一般的 HTML 事件有什么不同?
区别:
- 对于事件名称命名形式,原生事件为全小写,react 事件采纳小驼峰;
- 对于事件函数解决语法,原生事件为字符串,react 事件为函数;
- react 事件不能采纳 return false 的形式来阻止浏览器的默认行为,而必须要地明确地调用
preventDefault()
来阻止默认行为。
合成事件是 react 模仿原生 DOM 事件所有能力的一个事件对象,其长处如下:
- 兼容所有浏览器,更好的跨平台;
- 将事件对立寄存在一个数组,防止频繁的新增与删除(垃圾回收)。
- 不便 react 对立治理和事务机制。
事件的执行程序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为须要冒泡到 document 上合成事件才会执行。
React 的生命周期有哪些?
React 通常将组件生命周期分为三个阶段:
- 装载阶段(Mount),组件第一次在 DOM 树中被渲染的过程;
- 更新过程(Update),组件状态发生变化,从新更新渲染的过程;
- 卸载过程(Unmount),组件从 DOM 树中被移除的过程;
1)组件挂载阶段
挂载阶段组件被创立,而后组件实例插入到 DOM 中,实现组件的第一次渲染,该过程只会产生一次,在此阶段会顺次调用以下这些办法:
- constructor
- getDerivedStateFromProps
- render
- componentDidMount
(1)constructor
组件的构造函数,第一个被执行,若没有显式定义它,会有一个默认的构造函数,然而若显式定义了构造函数,咱们必须在构造函数中执行 super(props)
,否则无奈在构造函数中拿到 this。
如果不初始化 state 或不进行办法绑定,则不须要为 React 组件实现构造函数Constructor。
constructor 中通常只做两件事:
- 初始化组件的 state
- 给事件处理办法绑定 this
constructor(props) {super(props);
// 不要在构造函数中调用 setState,能够间接给 state 设置初始值
this.state = {counter: 0}
this.handleClick = this.handleClick.bind(this)
}
(2)getDerivedStateFromProps
static getDerivedStateFromProps(props, state)
这是个静态方法,所以不能在这个函数里应用 this
,有两个参数 props
和 state
,别离指接管到的新参数和以后组件的 state
对象,这个函数会返回一个对象用来更新以后的 state
对象,如果不须要更新能够返回 null
。
该函数会在装载时,接管到新的 props
或者调用了 setState
和 forceUpdate
时被调用。如当接管到新的属性想批改 state
,就能够应用。
// 当 props.counter 变动时,赋值给 state
class App extends React.Component {constructor(props) {super(props)
this.state = {counter: 0}
}
static getDerivedStateFromProps(props, state) {if (props.counter !== state.counter) {
return {counter: props.counter}
}
return null
}
handleClick = () => {
this.setState({counter: this.state.counter + 1})
}
render() {
return (
<div>
<h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1>
</div>
)
}
}
当初能够显式传入 counter
,然而这里有个问题,如果想要通过点击实现 state.counter
的减少,但这时会发现值不会产生任何变动,始终放弃 props
传进来的值。这是因为在 React 16.4^ 的版本中 setState
和 forceUpdate
也会触发这个生命周期,所以当组件外部 state
变动后,就会从新走这个办法,同时会把 state
值赋值为 props
的值。因而须要多加一个字段来记录之前的 props
值,这样就会解决上述问题。具体如下:
// 这里只列出须要变动的中央
class App extends React.Component {constructor(props) {super(props)
this.state = {
// 减少一个 preCounter 来记录之前的 props 传来的值
preCounter: 0,
counter: 0
}
}
static getDerivedStateFromProps(props, state) {
// 跟 state.preCounter 进行比拟
if (props.counter !== state.preCounter) {
return {
counter: props.counter,
preCounter: props.counter
}
}
return null
}
handleClick = () => {
this.setState({counter: this.state.counter + 1})
}
render() {
return (
<div>
<h1 onClick={this.handleClick}>Hello, world!{this.state.counter}</h1>
</div>
)
}
}
(3)render
render 是 React 中最外围的办法,一个组件中必须要有这个办法,它会依据状态 state
和属性 props
渲染组件。这个函数只做一件事,就是返回须要渲染的内容,所以不要在这个函数内做其余业务逻辑,通常调用该办法会返回以下类型中一个:
- React 元素:这里包含原生的 DOM 以及 React 组件;
- 数组和 Fragment(片段):能够返回多个元素;
- Portals(插槽):能够将子元素渲染到不同的 DOM 子树种;
- 字符串和数字:被渲染成 DOM 中的 text 节点;
- 布尔值或 null:不渲染任何内容。
(4)componentDidMount()
componentDidMount()会在组件挂载后(插入 DOM 树中)立刻调。该阶段通常进行以下操作:
- 执行依赖于 DOM 的操作;
- 发送网络申请;(官网倡议)
- 增加订阅音讯(会在 componentWillUnmount 勾销订阅);
如果在 componentDidMount
中调用 setState
,就会触发一次额定的渲染,多调用了一次 render
函数,因为它是在浏览器刷新屏幕前执行的,所以用户对此是没有感知的,然而我该当防止这样应用,这样会带来肯定的性能问题,尽量是在 constructor
中初始化 state
对象。
在组件装载之后,将计数数字变为 1:
class App extends React.Component {constructor(props) {super(props)
this.state = {counter: 0}
}
componentDidMount () {
this.setState({counter: 1})
}
render () {
return (
<div className="counter">
counter 值: {this.state.counter} </div>
)
}
}
2)组件更新阶段
当组件的 props
扭转了,或组件外部调用了 setState/forceUpdate
,会触发更新从新渲染,这个过程可能会产生屡次。这个阶段会顺次调用上面这些办法:
- getDerivedStateFromProps
- shouldComponentUpdate
- render
- getSnapshotBeforeUpdate
- componentDidUpdate
(1)shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
在说这个生命周期函数之前,来看两个问题:
- setState 函数在任何状况下都会导致组件从新渲染吗?例如上面这种状况:
this.setState({number: this.state.number})
- 如果没有调用 setState,props 值也没有变动,是不是组件就不会从新渲染?
第一个问题答案是 会,第二个问题如果是父组件从新渲染时,不论传入的 props 有没有变动,都会引起子组件的从新渲染。
那么有没有什么办法解决在这两个场景下不让组件从新渲染进而晋升性能呢?这个时候 shouldComponentUpdate
退场了,这个生命周期函数是用来晋升速度的,它是在从新渲染组件开始前触发的,默认返回 true
,能够比拟 this.props
和 nextProps
,this.state
和 nextState
值是否变动,来确认返回 true 或者 false
。当返回 false
时,组件的更新过程进行,后续的 render
、componentDidUpdate
也不会被调用。
留神: 增加 shouldComponentUpdate
办法时,不倡议应用深度相等查看(如应用 JSON.stringify()
),因为深比拟效率很低,可能会比从新渲染组件效率还低。而且该办法保护比拟艰难,倡议应用该办法会产生显著的性能晋升时应用。
(2)getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState)
这个办法在 render
之后,componentDidUpdate
之前调用,有两个参数 prevProps
和 prevState
,示意更新之前的 props
和 state
,这个函数必须要和 componentDidUpdate
一起应用,并且要有一个返回值,默认是 null
,这个返回值作为第三个参数传给 componentDidUpdate
。
(3)componentDidUpdate
componentDidUpdate() 会在更新后会被立刻调用,首次渲染不会执行此办法。该阶段通常进行以下操作:
- 当组件更新后,对 DOM 进行操作;
- 如果你对更新前后的 props 进行了比拟,也能够抉择在此处进行网络申请;(例如,当 props 未发生变化时,则不会执行网络申请)。
componentDidUpdate(prevProps, prevState, snapshot){}
该办法有三个参数:
- prevProps: 更新前的 props
- prevState: 更新前的 state
- snapshot: getSnapshotBeforeUpdate()生命周期的返回值
3)组件卸载阶段
卸载阶段只有一个生命周期函数,componentWillUnmount() 会在组件卸载及销毁之前间接调用。在此办法中执行必要的清理操作:
- 革除 timer,勾销网络申请或革除
- 勾销在 componentDidMount() 中创立的订阅等;
这个生命周期在一个组件被卸载和销毁之前被调用,因而你不应该再这个办法中应用 setState
,因为组件一旦被卸载,就不会再装载,也就不会从新渲染。
4)错误处理阶段
componentDidCatch(error, info),此生命周期在后辈组件抛出谬误后被调用。它接管两个参数∶
- error:抛出的谬误。
- info:带有 componentStack key 的对象,其中蕴含无关组件引发谬误的栈信息
React 常见的生命周期如下:React 常见生命周期的过程大抵如下:
- 挂载阶段,首先执行 constructor 构造方法,来创立组件
- 创立实现之后,就会执行 render 办法,该办法会返回须要渲染的内容
- 随后,React 会将须要渲染的内容挂载到 DOM 树上
- 挂载实现之后就会执行 componentDidMount 生命周期函数
- 如果咱们给组件创立一个 props(用于组件通信)、调用 setState(更改 state 中的数据)、调用 forceUpdate(强制更新组件)时,都会从新调用 render 函数
- render 函数从新执行之后,就会从新进行 DOM 树的挂载
- 挂载实现之后就会执行 componentDidUpdate 生命周期函数
- 当移除组件时,就会执行 componentWillUnmount 生命周期函数
React 次要生命周期总结:
- getDefaultProps:这个函数会在组件创立之前被调用一次(有且仅有一次),它被用来初始化组件的 Props;
- getInitialState:用于初始化组件的 state 值;
- componentWillMount:在组件创立后、render 之前,会走到 componentWillMount 阶段。这个阶段我集体始终没用过、十分鸡肋。起初 React 官网曾经不举荐大家在 componentWillMount 里做任何事件、到当初 React16 间接废除了这个生命周期,足见其鸡肋水平了;
- render:这是所有生命周期中惟一一个你必须要实现的办法。一般来说须要返回一个 jsx 元素,这时 React 会依据 props 和 state 来把组件渲染到界面上;不过有时,你可能不想渲染任何货色,这种状况下让它返回 null 或者 false 即可;
- componentDidMount:会在组件挂载后(插入 DOM 树中后)立刻调用,标记着组件挂载实现。一些操作如果依赖获取到 DOM 节点信息,咱们就会放在这个阶段来做。此外,这还是 React 官网举荐的发动 ajax 申请的机会。该办法和 componentWillMount 一样,有且仅有一次调用。
参考 前端进阶面试题具体解答
对 React SSR 的了解
服务端渲染是数据与模版组成的 html,即 HTML = 数据 + 模版。将组件或页面通过服务器生成 html 字符串,再发送到浏览器,最初将动态标记 ” 混合 ” 为客户端上齐全交互的应用程序。页面没应用服务渲染,当申请页面时,返回的 body 里为空,之后执行 js 将 html 构造注入到 body 里,联合 css 显示进去;
SSR 的劣势:
- 对 SEO 敌对
- 所有的模版、图片等资源都存在服务器端
- 一个 html 返回所有数据
- 缩小 HTTP 申请
- 响应快、用户体验好、首屏渲染快
1)更利于 SEO
不同爬虫工作原理相似,只会爬取源码,不会执行网站的任何脚本应用了 React 或者其它 MVVM 框架之后,页面大多数 DOM 元素都是在客户端依据 js 动静生成,可供爬虫抓取剖析的内容大大减少。另外,浏览器爬虫不会期待咱们的数据实现之后再去抓取页面数据。服务端渲染返回给客户端的是曾经获取了异步数据并执行 JavaScript 脚本的最终 HTML,网络爬中就能够抓取到残缺页面的信息。
2)更利于首屏渲染
首屏的渲染是 node 发送过去的 html 字符串,并不依赖于 js 文件了,这就会使用户更快的看到页面的内容。尤其是针对大型单页利用,打包后文件体积比拟大,一般客户端渲染加载所有所需文件工夫较长,首页就会有一个很长的白屏等待时间。
SSR 的局限:
1)服务端压力较大
原本是通过客户端实现渲染,当初对立到服务端 node 服务去做。尤其是高并发拜访的状况,会大量占用服务端 CPU 资源;
2)开发条件受限
在服务端渲染中,只会执行到 componentDidMount 之前的生命周期钩子,因而我的项目援用的第三方的库也不可用其它生命周期钩子,这对援用库的抉择产生了很大的限度;
3)学习老本绝对较高 除了对 webpack、MVVM 框架要相熟,还须要把握 node、Koa2 等相干技术。绝对于客户端渲染,我的项目构建、部署过程更加简单。
工夫耗时比拟:
1)数据申请
由服务端申请首屏数据,而不是客户端申请首屏数据,这是 ” 快 ” 的一个次要起因。服务端在内网进行申请,数据响应速度快。客户端在不同网络环境进行数据申请,且外网 http 申请开销大,导致时间差
- 客户端数据申请
-
服务端数据申请
2)html 渲染 服务端渲染是先向后端服务器申请数据,而后生成残缺首屏 html 返回给浏览器;而客户端渲染是等 js 代码下载、加载、解析实现后再申请数据渲染,期待的过程页面是什么都没有的,就是用户看到的白屏。就是服务端渲染不须要期待 js 代码下载实现并申请数据,就能够返回一个已有残缺数据的首屏页面。
- 非 ssr html 渲染
- ssr html 渲染
展现组件 (Presentational component) 和容器组件 (Container component) 之间有何不同
展现组件关怀组件看起来是什么。展现专门通过 props 承受数据和回调,并且简直不会有本身的状态,但当展现组件领有本身的状态时,通常也只关怀 UI 状态而不是数据的状态。
容器组件则更关怀组件是如何运作的。容器组件会为展现组件或者其它容器组件提供数据和行为 (behavior),它们会调用 Flux actions
,并将其作为回调提供给展现组件。容器组件常常是有状态的,因为它们是(其它组件的) 数据源。
React 的虚构 DOM 和 Diff 算法的外部实现
传统 diff 算法的工夫复杂度是 O(n^3),这在前端 render 中是不可承受的。为了升高工夫复杂度,react 的 diff 算法做了一些斗争,放弃了最优解,最终将工夫复杂度升高到了 O(n)。
那么 react diff 算法做了哪些斗争呢?,参考如下:
- tree diff:只比照同一层的 dom 节点,疏忽 dom 节点的跨层级挪动
如下图,react 只会对雷同色彩方框内的 DOM 节点进行比拟,即同一个父节点下的所有子节点。当发现节点不存在时,则该节点及其子节点会被齐全删除掉,不会用于进一步的比拟。
这样只须要对树进行一次遍历,便能实现整个 DOM 树的比拟。
这就意味着,如果 dom 节点产生了跨层级挪动,react 会删除旧的节点,生成新的节点,而不会复用。
- component diff:如果不是同一类型的组件,会删除旧的组件,创立新的组件
- element diff:对于同一层级的一组子节点,须要通过惟一 id 进行来辨别
- 如果没有 id 来进行辨别,一旦有插入动作,会导致插入地位之后的列表全副从新渲染
- 这也是为什么渲染列表时为什么要应用惟一的 key。
**
React 与 Vue 的 diff 算法有何不同?
diff 算法是指生成更新补丁的形式,次要利用于虚构 DOM 树变动后,更新实在 DOM。所以 diff 算法肯定存在这样一个过程:触发更新 → 生成补丁 → 利用补丁。
React 的 diff 算法,触发更新的机会次要在 state 变动与 hooks 调用之后。此时触发虚构 DOM 树变更遍历,采纳了深度优先遍历算法。但传统的遍历形式,效率较低。为了优化效率,应用了分治的形式。将繁多节点比对转化为了 3 种类型节点的比对,别离是树、组件及元素,以此晋升效率。
- 树比对:因为网页视图中较少有跨层级节点挪动,两株虚构 DOM 树只对同一档次的节点进行比拟。
- 组件比对:如果组件是同一类型,则进行树比对,如果不是,则间接放入到补丁中。
- 元素比对:次要产生在同层级中,通过标记节点操作生成补丁,节点操作对应实在的 DOM 剪裁操作。
以上是经典的 React diff 算法内容。自 React 16 起,引入了 Fiber 架构。为了使整个更新过程可随时暂停复原,节点与树别离采纳了 FiberNode 与 FiberTree 进行重构。fiberNode 应用了双链表的构造,能够间接找到兄弟节点与子节点。整个更新过程由 current 与 workInProgress 两株树双缓冲实现。workInProgress 更新实现后,再通过批改 current 相干指针指向新节点。
Vue 的整体 diff 策略与 React 对齐,尽管不足工夫切片能力,但这并不意味着 Vue 的性能更差,因为在 Vue 3 初期引入过,前期因为收益不高移除掉了。除了高帧率动画,在 Vue 中其余的场景简直都能够应用防抖和节流去进步响应性能。
类组件和函数组件有何不同?
解答
在 React 16.8 版本(引入钩子)之前,应用基于类的组件来创立须要保护外部状态或利用生命周期办法的组件(即 componentDidMount
和shouldComponentUpdate
)。基于类的组件是 ES6 类,它扩大了 React 的 Component 类,并且至多实现了 render()
办法。
类组件:
class Welcome extends React.Component {render() {return <h1>Hello, {this.props.name}</h1>;
}
}
函数组件是无状态的(同样,小于 React 16.8 版本),并返回要出现的输入。它们渲染 UI 的首选只依赖于属性,因为它们比基于类的组件更简略、更具性能。
函数组件:
function Welcome(props) {return <h1>Hello, {props.name}</h1>;
}
留神:在 React 16.8 版本中引入钩子意味着这些区别不再实用(请参阅 14 和 15 题)。
react 父子传值
父传子——在调用子组件上绑定,子组件中获取 this.props
子传父——援用子组件的时候传过来一个办法,子组件通过 this.props.methed()传过来参数
connection
React- Router 有几种模式?
有以下几种模式。
HashRouter,通过散列实现,路由要带 #。
BrowerRouter,利用 HTML5 中 history API 实现,须要服务器端反对,兼容性不是很好。
什么是上下文 Context
Context 通过组件树提供了一个传递数据的办法,从而防止了在每一个层级手动的传递 props 属性。
- 用法:在父组件上定义 getChildContext 办法,返回一个对象,而后它的子组件就能够通过 this.context 属性来获取
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Header extends Component{render() {
return (
<div>
<Title/>
</div>
)
}
}
class Title extends Component{
static contextTypes={color:PropTypes.string}
render() {
return (<div style={{color:this.context.color}}>
Title
</div>
)
}
}
class Main extends Component{render() {
return (
<div>
<Content>
</Content>
</div>
)
}
}
class Content extends Component{
static contextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
render() {
return (<div style={{color:this.context.color}}>
Content
<button onClick={()=>this.context.changeColor('green')}> 绿色 </button>
<button onClick={()=>this.context.changeColor('orange')}> 橙色 </button>
</div>
)
}
}
class Page extends Component{constructor() {super();
this.state={color:'red'};
}
static childContextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
getChildContext() {
return {
color: this.state.color,
changeColor:(color)=>{this.setState({color})
}
}
}
render() {
return (
<div>
<Header/>
<Main/>
</div>
)
}
}
ReactDOM.render(<Page/>,document.querySelector('#root'));
React Hooks 和生命周期的关系?
函数组件 的实质是函数,没有 state 的概念的,因而 不存在生命周期 一说,仅仅是一个 render 函数 而已。
然而引入 Hooks 之后就变得不同了,它能让组件在不应用 class 的状况下领有 state,所以就有了生命周期的概念,所谓的生命周期其实就是 useState
、useEffect()
和 useLayoutEffect()
。
即:Hooks 组件(应用了 Hooks 的函数组件)有生命周期,而函数组件(未应用 Hooks 的函数组件)是没有生命周期的。
上面是具体的 class 与 Hooks 的 生命周期对应关系:
constructor
:函数组件不须要构造函数,能够通过调用**useState 来初始化 state**
。如果计算的代价比拟低廉,也能够传一个函数给useState
。
const [num, UpdateNum] = useState(0)
getDerivedStateFromProps
:个别状况下,咱们不须要应用它,能够在 渲染过程中更新 state,以达到实现getDerivedStateFromProps
的目标。
function ScrollView({row}) {let [isScrollingDown, setIsScrollingDown] = useState(false);
let [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row 自上次渲染以来产生过扭转。更新 isScrollingDown。setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
React 会立刻退出第一次渲染并用更新后的 state 从新运行组件以防止消耗太多性能。
shouldComponentUpdate
:能够用**React.memo**
包裹一个组件来对它的props
进行浅比拟
const Button = React.memo((props) => {// 具体的组件});
留神:**React.memo 等效于 **
`PureComponent,它只浅比拟 props。这里也能够应用
useMemo` 优化每一个节点。
render
:这是函数组件体自身。componentDidMount
,componentDidUpdate
:useLayoutEffect
与它们两的调用阶段是一样的。然而,咱们举荐你 一开始先用 useEffect,只有当它出问题的时候再尝试应用useLayoutEffect
。useEffect
能够表白所有这些的组合。
// componentDidMount
useEffect(()=>{// 须要在 componentDidMount 执行的内容}, [])
useEffect(() => {
// 在 componentDidMount,以及 count 更改时 componentDidUpdate 执行的内容
document.title = `You clicked ${count} times`;
return () => {
// 须要在 count 更改时 componentDidUpdate(先于 document.title = ... 执行,恪守先清理后更新)// 以及 componentWillUnmount 执行的内容
} // 当函数中 Cleanup 函数会依照在代码中定义的程序先后执行,与函数自身的个性无关
}, [count]); // 仅在 count 更改时更新
请记得 React 会期待浏览器实现画面渲染之后才会提早调用,因而会使得额定操作很不便
componentWillUnmount
:相当于useEffect
外面返回的cleanup
函数
// componentDidMount/componentWillUnmount
useEffect(()=>{
// 须要在 componentDidMount 执行的内容
return function cleanup() {// 须要在 componentWillUnmount 执行的内容}
}, [])
componentDidCatch
andgetDerivedStateFromError
:目前 还没有 这些办法的 Hook 等价写法,但很快会加上。
class 组件 | Hooks 组件 |
---|---|
constructor | useState |
getDerivedStateFromProps | useState 外面 update 函数 |
shouldComponentUpdate | useMemo |
render | 函数自身 |
componentDidMount | useEffect |
componentDidUpdate | useEffect |
componentWillUnmount | useEffect 外面返回的函数 |
componentDidCatch | 无 |
getDerivedStateFromError | 无 |
React 组件命名举荐的形式是哪个?
通过援用而不是应用来命名组件 displayName。
应用 displayName 命名组件:
export default React.createClass({displayName: 'TodoApp', // ...})
React 举荐的办法:
export default class TodoApp extends React.Component {// ...}
React 和 vue.js 的相似性和差异性是什么?
相似性如下。
(1)都是用于创立 UI 的 JavaScript 库。
(2)都是疾速和轻量级的代码库(这里指 React 外围库)。
(3)都有基于组件的架构。
(4)都应用虚构 DOM。
(5)都能够放在独自的 HTML 文件中,或者放在 Webpack 设置的一个更简单的模块中。
(6)都有独立但罕用的路由器和状态治理库。
它们最大的区别在于 Vue. js 通常应用 HTML 模板文件,而 React 齐全应用 JavaScript 创立虚构 DOM。Vue. js 还具备对于“可变状态”的“reactivity”的从新渲染的自动化检测零碎。
redux 中间件
中间件提供第三方插件的模式,自定义拦挡
action
->reducer
的过程。变为action
->middlewares
->reducer
。这种机制能够让咱们扭转数据流,实现如异步action
,action
过滤,日志输入,异样报告等性能
redux-logger
:提供日志输入redux-thunk
:解决异步操作redux-promise
:解决异步操作,actionCreator
的返回值是promise
React 中的 props 为什么是只读的?
this.props
是组件之间沟通的一个接口,原则上来讲,它只能从父组件流向子组件。React 具备浓厚的函数式编程的思维。
提到函数式编程就要提一个概念:纯函数。它有几个特点:
- 给定雷同的输出,总是返回雷同的输入。
- 过程没有副作用。
- 不依赖内部状态。
this.props
就是吸取了纯函数的思维。props 的不能够变性就保障的雷同的输出,页面显示的内容是一样的,并且不会产生副作用
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 的预处理操作。