給componentWillMount componentWillReceiveProps componentWillUpdate生命周期加上UNSAFE_前綴,表明其不安全性,並將在未來版本將其移除
官網文檔指出使用這些生命周期的代碼會在未來版本的react中更容易產生bug,尤其是對於異步渲染的版本 新增生命周期static getDerivedStateFromProps(prevProps, prevState)、getSnapshotBeforeUpdate(prevProps, prevState) 、componendDidCatch(error, info)
static getDerivedStateFromProps(prevProps, prevState) 在每次渲染之前都會調用,不管造成重新渲染的原因,不管初始掛載還是后面的更新都會調用,這一點和UNSAFE_componentWillReceiveProps不同(只有當父組件造成重新渲染時才調用),每次都應該返回一個對象作為state的更新,或者返回null表示不更新 它的使用場景一般為依賴於props的變化去做一些狀態的更新,讓我們能夠根據props的變化去更新內部的狀態,以前我們經常在componentWillReceiveProps中完成該操作 但是你需要考慮是否真的有必要使用這個生命周期,比如: 如果你需要根據網絡請求獲取數據,你可以在componentDidUpdate里完成 當props改變時,你需要去重新計算某些數據,可以使用memoization helper替代 當props改變時,如果你想要重置一些state,可以考慮使用Fully controlled component(完全移出state的使用,通過父組件控制數據)或者Fully uncontrolled component(數據僅存在內部狀態中)
getSnapshotBeforeUpdate(prevProps,prevState) 在最新的渲染數據提交給DOM前會立即調用,它讓你在組件的數據可能要改變之前獲取他們,他的返回值會被傳遞給componentDidUpdate的第三個參數 componentDidCatch 如果一個組件定義了componentDidCatch生命周期,則他將成為一個錯誤邊界(錯誤邊界會捕捉渲染期間、在生命周期方法中和在它們之下整棵樹的構造函數中的錯誤,就像使用了try catch,不會將錯誤直接拋出了,保證應用的可用性)
class A extends React.Component {
// 用於初始化 state
constructor() {}
// 用於替換 `componentWillReceiveProps` ,該函數會在初始化和 `update` 時被調用
// 因為該函數是靜態函數,所以取不到 `this`
// 如果需要對比 `prevProps` 需要單獨在 `state` 中維護
static getDerivedStateFromProps(nextProps, prevState) {}
// 判斷是否需要更新組件,多用於組件性能優化
shouldComponentUpdate(nextProps, nextState) {}
// 組件掛載后調用
// 可以在該函數中進行請求或者訂閱
componentDidMount() {}
// 用於獲得最新的 DOM 數據
getSnapshotBeforeUpdate() {}
// 組件即將銷毀
// 可以在此處移除訂閱,定時器等等
componentWillUnmount() {}
// 組件銷毀后調用
componentDidUnMount() {}
// 組件更新后調用
componentDidUpdate() {}
// 渲染組件函數
render() {}
// 以下函數不建議使用
UNSAFE_componentWillMount() {}
UNSAFE_componentWillUpdate(nextProps, nextState) {}
UNSAFE_componentWillReceiveProps(nextProps) {}
}
getDerivedStateFromProps內部不可以有副作用,因為現在是無論是state改變還是props改變,
都會執行它。
例如:
這種寫法會導致多次循環渲染直到報錯
class App extends Component { constructor(props){ super(props) this.myFetch=this.myFetch.bind(this) this.state = { name: "", list: null, myFetch:this.myFetch }; } static getDerivedStateFromProps(props, state) { if ( props.name !== state.name ) { // 這一句是有副作用的,它會改變state狀態, // 然后再次調用getDerivedStateFromProps,再次改變state狀態... state.myFetch(props.name) return { name: props.name }; } return null; } myFetch(){ this.setState({ list: "newList" }) } render() { return ( <div>{this.state.list}</div> ); } }
以上正確寫法應為:
class App extends Component { constructor(props){ super(props) this.myFetch=this.myFetch.bind(this) this.state = { name: "", list: null, //myFetch:this.myFetch }; } // 純函數,無副作用 static getDerivedStateFromProps(props, state) { if ( props.name !== state.name ) { return { name: props.name, list: null }; } return null; } componentDidUpdate(){ if(!this.state.list){ this.myFetch(this.props.name) } } // 看是否需要初始化的時候調用 componentDidMount(){ this.myFetch(this.props.name) } myFetch(){ this.setState({ list: "newList" }) } render() { return ( <div>{this.state.list}</div> ); } }
