react diff 算法
咱们晓得React会保护两个虚构DOM,那么是如何来比拟,如何来判断,做出最优的解呢?这就用到了diff算法
diff算法的作用
计算出Virtual DOM中真正变动的局部,并只针对该局部进行原生DOM操作,而非从新渲染整个页面。
传统diff算法
通过循环递归对节点进行顺次比照,算法复杂度达到 O(n^3)
,n是树的节点数,这个有多可怕呢?——如果要展现1000个节点,得执行上亿次比拟。。即使是CPU快能执行30亿条命令,也很难在一秒内计算出差别。
React的diff算法
- 什么是和谐?
将Virtual DOM树转换成actual DOM树的起码操作的过程 称为 和谐 。
- 什么是React diff算法?
diff
算法是和谐的具体实现。
diff策略
React用 三大策略 将O(n^3)
杂度 转化为O(n)
复杂度
策略一(tree diff):
- Web UI中DOM节点跨层级的挪动操作特地少,能够忽略不计
- 同级比拟,既然DOM 节点跨层级的挪动操作少到能够忽略不计,那么React通过updateDepth 对 Virtual DOM 树进行层级管制,也就是同一层,在比照的过程中,如果发现节点不在了,会齐全删除不会对其余中央进行比拟,这样只须要对树遍历一次就OK了
策略二(component diff):
- 领有雷同类的两个组件 生成类似的树形构造,
- 领有不同类的两个组件 生成不同的树形构造。
策略三(element diff):
对于同一层级的一组子节点,通过惟一id辨别。
tree diff
- React通过updateDepth对Virtual DOM树进行层级管制。
- 对树分层比拟,两棵树 只对同一档次节点 进行比拟。如果该节点不存在时,则该节点及其子节点会被齐全删除,不会再进一步比拟。
- 只需遍历一次,就能实现整棵DOM树的比拟。
那么问题来了,如果DOM节点呈现了跨层级操作,diff会咋办呢?
答:diff只简略思考同层级的节点地位变换,如果是跨层级的话,只有创立节点和删除节点的操作。
如上图所示,以A为根节点的整棵树会被从新创立,而不是挪动,因而 官网倡议不要进行DOM节点跨层级操作,能够通过CSS暗藏、显示节点,而不是真正地移除、增加DOM节点
component diff
React对不同的组件间的比拟,有三种策略
- 同一类型的两个组件,按原策略(层级比拟)持续比拟Virtual DOM树即可。
- 同一类型的两个组件,组件A变动为组件B时,可能Virtual DOM没有任何变动,如果晓得这点(变换的过程中,Virtual DOM没有扭转),可节俭大量计算工夫,所以 用户 能够通过
shouldComponentUpdate()
来判断是否须要 判断计算。 - 不同类型的组件,将一个(将被扭转的)组件判断为
dirty component
(脏组件),从而替换 整个组件的所有节点。
留神:如果组件D和组件G的构造类似,然而 React判断是 不同类型的组件,则不会比拟其构造,而是删除 组件D及其子节点,创立组件G及其子节点。
element diff
当节点处于同一层级时,diff提供三种节点操作:删除、插入、挪动。
- 插入:组件 C 不在汇合(A,B)中,须要插入
删除:
- 组件 D 在汇合(A,B,D)中,但 D的节点曾经更改,不能复用和更新,所以须要删除 旧的 D ,再创立新的。
- 组件 D 之前在 汇合(A,B,D)中,但汇合变成新的汇合(A,B)了,D 就须要被删除。
- 挪动:组件D曾经在汇合(A,B,C,D)里了,且汇合更新时,D没有产生更新,只是地位扭转,如新汇合(A,D,B,C),D在第二个,毋庸像传统diff,让旧汇合的第二个B和新汇合的第二个D 比拟,并且删除第二个地位的B,再在第二个地位插入D,而是 (对同一层级的同组子节点) 增加惟一key进行辨别,挪动即可。
diff的有余与待优化的中央
尽量减少相似将最初一个节点挪动到列表首部的操作,当节点数量过大或更新操作过于频繁时,会影响React的渲染性能
react-router4的外围
- 路由变成了组件
- 扩散到各个页面,不须要配置 比方
<link> <route></route>
什么是 React Fiber?
Fiber 是 React 16 中新的协调引擎或从新实现外围算法。它的次要指标是反对虚构DOM的增量渲染。React Fiber 的指标是进步其在动画、布局、手势、暂停、停止或重用等方面的适用性,并为不同类型的更新调配优先级,以及新的并发原语。
React Fiber 的指标是加强其在动画、布局和手势等畛域的适用性。它的次要个性是增量渲染:可能将渲染工作宰割成块,并将其扩散到多个帧中。
如何 React.createElement ?
const element = <h1 className="greeting">Hello, world!</h1>;
上述代码如何应用 React.createElement
来实现:
const element = React.createElement("h1", { className: "greeting" }, "Hello, world!");
如何创立 refs
Refs 是应用 React.createRef()
创立的,并通过 ref
属性附加到 React 元素。在结构组件时,通常将 Refs
调配给实例属性,以便能够在整个组件中援用它们。
class MyComponent extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); } render() { return <div ref={this.myRef} />; }}
或者这样用:
class UserForm extends Component { handleSubmit = () => { console.log("Input Value is: ", this.input.value); }; render() { return ( <form onSubmit={this.handleSubmit}> <input type="text" ref={(input) => (this.input = input)} /> // Access DOM input in handle submit <button type="submit">Submit</button> </form> ); }}
这三个点(...)在 React 干嘛用的?
...
在React(应用JSX)代码中做什么?它叫什么?
<Modal {...this.props} title='Modal heading' animation={false}/>
这个叫扩大操作符号或者开展操作符,例如,如果this.props
蕴含a:1
和b:2
,则
<Modal {...this.props} title='Modal heading' animation={false}>
等价于上面内容:
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
扩大符号不仅实用于该用例,而且对于创立具备现有对象的大多数(或全副)属性的新对象十分不便,在更新state
咱们就常常这么做:
this.setState((prevState) => { return { foo: { ...prevState.foo, a: "updated" } };});
参考 前端进阶面试题具体解答
如何配置 React-Router 实现路由切换
(1)应用<Route>
组件
路由匹配是通过比拟 <Route>
的 path 属性和以后地址的 pathname 来实现的。当一个 <Route>
匹配胜利时,它将渲染其内容,当它不匹配时就会渲染 null。没有门路的 <Route>
将始终被匹配。
// when location = { pathname: '/about' }<Route path='/about' component={About}/> // renders <About/><Route path='/contact' component={Contact}/> // renders null<Route component={Always}/> // renders <Always/>
(2)联合应用 <Switch>
组件和 <Route>
组件
<Switch>
用于将 <Route>
分组。
<Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/contact" component={Contact} /></Switch>
<Switch>
不是分组 <Route>
所必须的,但他通常很有用。 一个 <Switch>
会遍历其所有的子 <Route>
元素,并仅渲染与以后地址匹配的第一个元素。
(3)应用 <Link>、 <NavLink>、<Redirect>
组件
<Link>
组件来在你的应用程序中创立链接。无论你在何处渲染一个<Link>
,都会在应用程序的 HTML 中渲染锚(<a>
)。
<Link to="/">Home</Link> // <a href='/'>Home</a>
是一种非凡类型的 当它的 to属性与以后地址匹配时,能够将其定义为"沉闷的"。
// location = { pathname: '/react' }<NavLink to="/react" activeClassName="hurray"> React</NavLink>// <a href='/react' className='hurray'>React</a>
当咱们想强制导航时,能够渲染一个<Redirect>
,当一个<Redirect>
渲染时,它将应用它的to属性进行定向。
useEffect 与 useLayoutEffect 的区别
(1)共同点
- 使用成果: useEffect 与 useLayoutEffect 两者都是用于解决副作用,这些副作用包含扭转 DOM、设置订阅、操作定时器等。在函数组件外部操作副作用是不被容许的,所以须要应用这两个函数去解决。
- 应用形式: useEffect 与 useLayoutEffect 两者底层的函数签名是完全一致的,都是调用的 mountEffectImpl办法,在应用上也没什么差别,根本能够间接替换。
(2)不同点
- 应用场景: useEffect 在 React 的渲染过程中是被异步调用的,用于绝大多数场景;而 useLayoutEffect 会在所有的 DOM 变更之后同步调用,次要用于解决 DOM 操作、调整款式、防止页面闪动等问题。也正因为是同步解决,所以须要防止在 useLayoutEffect 做计算量较大的耗时工作从而造成阻塞。
- 应用成果: useEffect是依照程序执行代码的,扭转屏幕像素之后执行(先渲染,后扭转DOM),当扭转屏幕内容时可能会产生闪动;useLayoutEffect是扭转屏幕像素之前就执行了(会推延页面显示的事件,先扭转DOM后渲染),不会产生闪动。useLayoutEffect总是比useEffect先执行。
在将来的趋势上,两个 API 是会长期共存的,临时没有删减合并的打算,须要开发者依据场景去自行抉择。React 团队的倡议十分实用,如果切实分不清,先用 useEffect,个别问题不大;如果页面有异样,再间接替换为 useLayoutEffect 即可。
react 最新版本解决了什么问题,减少了哪些货色
React 16.x的三大新个性 Time Slicing、Suspense、 hooks
- Time Slicing(解决CPU速度问题)使得在执行工作的期间能够随时暂停,跑去干别的事件,这个个性使得react能在性能极其差的机器跑时,依然放弃有良好的性能
- Suspense (解决网络IO问题) 和lazy配合,实现异步加载组件。 能暂停以后组件的渲染, 当实现某件事当前再持续渲染,解决从react出世到当初都存在的「异步副作用」的问题,而且解决得非的优雅,应用的是 T异步然而同步的写法,这是最好的解决异步问题的形式
- 提供了一个内置函数componentDidCatch,当有谬误产生时,能够敌对地展现 fallback 组件; 能够捕捉到它的子元素(包含嵌套子元素)抛出的异样; 能够复用谬误组件。
(1)React16.8 退出hooks,让React函数式组件更加灵便,hooks之前,React存在很多问题:
- 在组件间复用状态逻辑很难
- 简单组件变得难以了解,高阶组件和函数组件的嵌套过深。
- class组件的this指向问题
- 难以记忆的生命周期
hooks很好的解决了上述问题,hooks提供了很多办法
- useState 返回有状态值,以及更新这个状态值的函数
- useEffect 承受蕴含命令式,可能有副作用代码的函数。
- useContext 承受上下文对象(从 React.createContext返回的值)并返回以后上下文值,
- useReducer useState 的代替计划。承受类型为 (state,action)=> newState的reducer,并返回与dispatch办法配对的以后状态。
- useCalLback 返回一个回顾的memoized版本,该版本仅在其中一个输出产生更改时才会更改。纯函数的输入输出确定性 o useMemo 纯的一个记忆函数 o useRef 返回一个可变的ref对象,其Current 属性被初始化为传递的参数,返回的 ref 对象在组件的整个生命周期内放弃不变。
- useImperativeMethods 自定义应用ref时公开给父组件的实例值
- useMutationEffect 更新兄弟组件之前,它在React执行其DOM扭转的同一阶段同步触发
- useLayoutEffect DOM扭转后同步触发。应用它来从DOM读取布局并同步从新渲染
(2)React16.9
- 重命名 Unsafe 的生命周期办法。新的 UNSAFE_前缀将有助于在代码 review 和 debug 期间,使这些有问题的字样更突出
- 废除 javascrip:模式的 URL。以javascript:结尾的URL 非常容易蒙受攻打,造成安全漏洞。
- 废除"Factory"组件。 工厂组件会导致 React 变大且变慢。
- act()也反对异步函数,并且你能够在调用它时应用 await。
- 应用 <React.ProfiLer> 进行性能评估。在较大的利用中追踪性能回归可能会很不便
(3)React16.13.0
- 反对在渲染期间调用setState,但仅实用于同一组件
- 可检测抵触的款式规定并记录正告
- 废除 unstable_createPortal,应用CreatePortal
- 将组件堆栈增加到其开发正告中,使开发人员可能隔离bug并调试其程序,这能够分明地阐明问题所在,并更快地定位和修复谬误。
React.forwardRef有什么用
forwardRef
- 应用
forwardRef
(forward
在这里是「传递」的意思)后,就能跨组件传递ref
。 - 在例子中,咱们将
inputRef
从Form
跨组件传递到MyInput
中,并与input
产生关联
const MyInput = forwardRef((props, ref) => { return <input {...props} ref={ref} />;});function Form() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <MyInput ref={inputRef} /> <button onClick={handleClick}> Focus the input </button> </> );}
useImperativeHandle
除了「限度跨组件传递ref
」外,还有一种「避免ref
失控的措施」,那就是useImperativeHandle
,他的逻辑是这样的:既然「ref失控」
是因为「应用了不该被应用的DOM办法」(比方appendChild
),那我能够限度「ref
中只存在能够被应用的办法」。用useImperativeHandle
批改咱们的MyInput组件:
const MyInput = forwardRef((props, ref) => { const realInputRef = useRef(null); useImperativeHandle(ref, () => ({ focus() { realInputRef.current.focus(); }, })); return <input {...props} ref={realInputRef} />;});
当初,Form
组件中通过inputRef.current
只能取到如下数据结构:
{ focus() { realInputRef.current.focus(); },}
就杜绝了「开发者通过ref取到DOM后,执行不该被应用的API,呈现ref失控」
的状况
- 为了避免错用/滥用导致
ref
失控,React限度「默认状况下,不能跨组件传递ref」
- 为了破除这种限度,能够应用
forwardRef
。 - 为了缩小
ref
对DOM
的滥用,能够应用useImperativeHandle
限度ref
传递的数据结构。
React 高阶组件、Render props、hooks 有什么区别,为什么要一直迭代
这三者是目前react解决代码复用的次要形式:
- 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。
- render props是指一种在 React 组件之间应用一个值为函数的 prop 共享代码的简略技术,更具体的说,render prop 是一个用于告知组件须要渲染什么内容的函数 prop。
- 通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个应用场景更加简略。这两种模式仍有用武之地,(例如,一个虚构滚动条组件或者会有一个 renderltem 属性,或是一个可见的容器组件或者会有它本人的 DOM 构造)。但在大部分场景下,Hook 足够了,并且可能帮忙缩小嵌套。
(1)HOC 官网解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。
简言之,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 <WrappedComponent data={this.state.data} {...this.props} />; } };// 应用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
HOC的优缺点∶
- 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
- 毛病∶ hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩
(2)Render props 官网解释∶
"render prop"是指一种在 React 组件之间应用一个值为函数的 prop 共享代码的简略技术
具备render prop 的组件承受一个返回React元素的函数,将render的渲染逻辑注入到组件外部。在这里,"render"的命名能够是任何其余无效的标识符。
// DataProvider组件外部的渲染逻辑如下class DataProvider extends React.Components { state = { name: 'Tom' } render() { return ( <div> <p>共享数据组件本人外部的渲染逻辑</p> { this.props.render(this.state) } </div> ); }}// 调用形式<DataProvider render={data => ( <h1>Hello {data.name}</h1>)}/>
由此能够看到,render props的优缺点也很显著∶
- 长处:数据共享、代码复用,将组件内的state作为props传递给调用者,将渲染逻辑交给调用者。
- 毛病:无奈在 return 语句外拜访数据、嵌套写法不够优雅
(3)Hooks 官网解释∶
Hook是 React 16.8 的新增个性。它能够让你在不编写 class 的状况下应用 state 以及其余的 React 个性。通过自定义hook,能够复用代码逻辑。
// 自定义一个获取订阅数据的hookfunction useSubscription() { const data = DataSource.getComments(); return [data];}// function CommentList(props) { const {data} = props; const [subData] = useSubscription(); ...}// 应用<CommentList data='hello' />
以上能够看出,hook解决了hoc的prop笼罩的问题,同时应用的形式解决了render props的嵌套天堂的问题。hook的长处如下∶
- 应用直观;
- 解决hoc的prop 重名问题;
- 解决render props 因共享数据 而呈现嵌套天堂的问题;
- 能在return之外应用数据的问题。
须要留神的是:hook只能在组件顶层应用,不可在分支语句中应用。、
为什么 React 元素有一个 $$typeof 属性
目标是为了避免 XSS 攻打。因为 Synbol 无奈被序列化,所以 React 能够通过有没有 $$typeof 属性来断出以后的 element 对象是从数据库来的还是本人生成的。
- 如果没有 $$typeof 这个属性,react 会回绝解决该元素。
- 在 React 的古老版本中,上面的写法会呈现 XSS 攻打:
// 服务端容许用户存储 JSONlet expectedTextButGotJSON = { type: 'div', props: { dangerouslySetInnerHTML: { __html: '/* 把你想的搁着 */' }, }, // ...};let message = { text: expectedTextButGotJSON };// React 0.13 中有危险<p> {message.text}</p>
react router
import React from 'react'import { render } from 'react-dom'import { browserHistory, Router, Route, IndexRoute } from 'react-router'import App from '../components/App'import Home from '../components/Home'import About from '../components/About'import Features from '../components/Features'render( <Router history={browserHistory}> // history 路由 <Route path='/' component={App}> <IndexRoute component={Home} /> <Route path='about' component={About} /> <Route path='features' component={Features} /> </Route> </Router>, document.getElementById('app'))render( <Router history={browserHistory} routes={routes} />, document.getElementById('app'))
React Router 提供一个routerWillLeave生命周期钩子,这使得 React组件能够拦挡正在产生的跳转,或在来到route前提醒用户。routerWillLeave返回值有以下两种:
return
false
勾销此次跳转return
返回提示信息,在来到 route 前提醒用户进行确认。
高阶组件
高阶函数:如果一个函数承受一个或多个函数作为参数或者返回一个函数就可称之为高阶函数。
高阶组件:如果一个函数 承受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件。
react 中的高阶组件
React 中的高阶组件次要有两种模式:属性代理和反向继承。
属性代理 Proxy
- 操作
props
- 抽离
state
- 通过
ref
拜访到组件实例 - 用其余元素包裹传入的组件
WrappedComponent
反向继承
会发现其属性代理和反向继承的实现有些相似的中央,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component
,反向继承中继承的是传入的组件 WrappedComponent
。
反向继承能够用来做什么:
1.操作 state
高阶组件中能够读取、编辑和删除WrappedComponent
组件实例中的state
。甚至能够减少更多的state
项,然而十分不倡议这么做因为这可能会导致state
难以保护及治理。
function withLogging(WrappedComponent) { return class extends WrappedComponent { render() { return ( <div>; <h2>;Debugger Component Logging...<h2>; <p>;state:<p>; <pre>;{JSON.stringify(this.state, null, 4)}<pre>; <p>props:<p>; <pre>{JSON.stringify(this.props, null, 4)}<pre>; {super.render()} <div>; ); } }; }
2.渲染劫持(Render Highjacking)
条件渲染通过 props.isLoading 这个条件来判断渲染哪个组件。
批改由 render() 输入的 React 元素树
为什么应用jsx的组件中没有看到应用react却须要引入react?
实质上来说JSX是React.createElement(component, props, ...children)
办法的语法糖。在React 17之前,如果应用了JSX,其实就是在应用React, babel
会把组件转换为 CreateElement
模式。在React 17之后,就不再须要引入,因为 babel
曾经能够帮咱们主动引入react。
useEffect(fn, []) 和 componentDidMount 有什么差别
useEffect
会捕捉props
和 state。所以即使在回调函数里,你拿到的还是初始的 props 和 state。如果想得到“最新”的值,能够应用 ref。
react中这两个生命周期会触发死循环
componentWillUpdate
生命周期在shouldComponentUpdate
返回true后被触发。在这两个生命周期只有视图更新就会触发,因而不能再这两个生命周期中应用setState。否则会导致死循环
在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-Intl 的了解,它的工作原理?
React-intl是雅虎的语言国际化开源我的项目FormatJS的一部分,通过其提供的组件和API能够与ReactJS绑定。
React-intl提供了两种应用办法,一种是援用React组件,另一种是间接调取API,官网更加举荐在React我的项目中应用前者,只有在无奈应用React组件的中央,才应该调用框架提供的API。它提供了一系列的React组件,包含数字格式化、字符串格式化、日期格式化等。
在React-intl中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。
新版生命周期
在新版本中,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来间接阻止前面的逻辑执行,通常是用于做条件渲染,优化渲染的性能。