- React16新的生命周期棄用了componentWillMount股淡、componentWillReceivePorps胰默,componentWillUpdate
- 新增了getDerivedStateFromProps岩齿、getSnapshotBeforeUpdate來代替棄用的三個(gè)鉤子函數(shù)(componentWillMount缎玫、componentWillReceivePorps,componentWillUpdate)
- React16并沒有刪除這三個(gè)鉤子函數(shù),但是不能和新增的鉤子函數(shù)(getDerivedStateFromProps涝开、getSnapshotBeforeUpdate)混用,React17將會(huì)刪除componentWillMount框仔、componentWillReceivePorps舀武,componentWillUpdate
- 新增了對(duì)錯(cuò)誤的處理(componentDidCatch)
getDerivedStateFromProps
新的靜態(tài)getDerivedStateFromProps生命周期在組件實(shí)例化以及接收新props后調(diào)用。它可以返回一個(gè)對(duì)象來更新state离斩,或者返回null來表示新的props不需要任何state更新银舱。
與componentDidUpdate一起,這個(gè)新的生命周期將覆蓋舊版componentWillUpdate的所有用例捐腿。
getSnapshotBeforeUpdate
新的getSnapshotBeforeUpdate生命周期在更新之前被調(diào)用(例如纵朋,在DOM被更新之前)。此生命周期的返回值將作為第三個(gè)參數(shù)傳遞給componentDidUpdate茄袖。 (這個(gè)生命周期不是經(jīng)常需要的操软,但可以用于在恢復(fù)期間手動(dòng)保存滾動(dòng)位置的情況。)
與componentDidUpdate一起宪祥,這個(gè)新的生命周期應(yīng)該覆蓋傳統(tǒng)componentWillReceiveProps的所有用例聂薪。
React15部分生命周期函數(shù)的副作用
1.props改變的副作用
與componentWillUpdate一樣,componentWillReceiveProps可能會(huì)多次調(diào)用但是只更新一次蝗羊。出于這個(gè)原因藏澳,避免在此方法中導(dǎo)致的副作用非常重要。相反耀找,應(yīng)該使用componentDidUpdate翔悠,因?yàn)樗WC每次更新只調(diào)用一次。
2.在更新之前讀取DOM屬性
下面是一個(gè)組件的例子野芒,它在更新之前從DOM中讀取屬性蓄愁,以便在列表中保持滾動(dòng)位置。
class ScrollingList extends React.Component {
listRef = null;
previousScrollOffset = null;
componentWillUpdate(nextProps, nextState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (this.props.list.length < nextProps.list.length) {
this.previousScrollOffset =
this.listRef.scrollHeight - this.listRef.scrollTop;
}
}
componentDidUpdate(prevProps, prevState) {
// If previousScrollOffset is set, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
if (this.previousScrollOffset !== null) {
this.listRef.scrollTop =
this.listRef.scrollHeight -
this.previousScrollOffset;
this.previousScrollOffset = null;
}
}
render() {
return (
`<div>`
{/* ...contents... */}
`</div>`
);
}
setListRef = ref => {
this.listRef = ref;
};
}
在上面的例子中狞悲,componentWillUpdate被用來讀取DOM屬性撮抓。但是,對(duì)于異步渲染摇锋,“render”階段生命周期(如componentWillUpdate和render)與“commit”階段生命周期(如componentDidUpdate)之間可能存在延遲丹拯。如果用戶在這段時(shí)間內(nèi)做了類似調(diào)整窗口大小的操作,則從componentWillUpdate中讀取的scrollHeight值將失效荸恕。
解決此問題的方法是使用新的“commit”階段生命周期getSnapshotBeforeUpdate乖酬。在數(shù)據(jù)發(fā)生變化之前立即調(diào)用該方法(例如,在更新DOM之前)融求。它可以將React的值作為參數(shù)傳遞給componentDidUpdate剑刑,在數(shù)據(jù)發(fā)生變化后立即調(diào)用它。
這兩個(gè)生命周期可以像這樣一起使用:
class ScrollingList extends React.Component {
listRef = null;
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
return (
this.listRef.scrollHeight - this.listRef.scrollTop
);
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
this.listRef.scrollTop =
this.listRef.scrollHeight - snapshot;
}
}
render() {
return (
`<div>`
{/* ...contents... */}
`</div>`
);
}
setListRef = ref => {
this.listRef = ref;
};
}
PS:如果您正在編寫共享組件双肤,那么react-lifecycles-compat polyfill
可以使新的getSnapshotBeforeUpdate
生命周期與舊版本的React一起使用施掏。詳細(xì)了解如何使用它。
開源項(xiàng)目維護(hù)者
當(dāng)React 16.3發(fā)布時(shí)茅糜,我們還將發(fā)布一個(gè)新的npm包七芭, react-lifecycles-compat
。該npm包會(huì)填充組件蔑赘,以便新的getDerivedStateFromProps
和getSnapshotBeforeUpdate
生命周期也可以與舊版本的React(0.14.9+)一起使用狸驳。
要使用這個(gè)polyfill,首先將它作為依賴項(xiàng)添加到您的庫中:
# Yarn
yarn add react-lifecycles-compat
# NPM
npm install react-lifecycles-compat --save
使用polyfill將組件向后兼容舊版本的React:
import React from 'react';
import {polyfill} from 'react-lifecycles-compat';
class ExampleComponent extends React.Component {
static getDerivedStateFromProps(nextProps, prevState) {
// Your state update logic here ...
}
}
// Polyfill your component to work with older versions of React:
polyfill(ExampleComponent);
export default ExampleComponent;
參考博客:
https://segmentfault.com/a/1190000014456811?utm_source=channel-hottest
https://segmentfault.com/a/1190000016617400
https://www.cnblogs.com/tianshu/p/9313945.html
https://blog.csdn.net/wust_cyl/article/details/84306393