在 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
能够表白所有这些的组合。
// componentDidMountuseEffect(()=>{ // 须要在 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/componentWillUnmountuseEffect(()=>{ // 须要在 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的预处理操作。