React 之前的版本有一個 lifecycle componentWillReceiveProps,主要是如果 props 有發生改變則會觸發此 lifecycle。但現在的 React 則拔掉了這個 lifecycle,取而代之的是 getDerivedStateFromProps。那是為什麼呢?原因是因為 React 團隊不希望使用者一直用 componentWillReceiveProps 這個 lifecycle,但他又太好用了,所以把它改為 getDerivedStateFromProps(名字變長也變臭...)
來看一下簡單的範例
class ChildComponent1 extends React.Component {
constructor(props) {
super(props);
this.state = {
display: `${this.props.counter} times`
}
}
static getDerivedStateFromProps(props, state) {
if (props.counter === 1) {
return null
}
return {
display: `${props.counter} times`
};
}
render() {
return (
<h1>{this.state.display}</h1>
)
}
}
const App = () => {
const [counter, setCounter] = useState(0);
return (
<div>
<button onClick={() => { setCounter(counter + 1) }}>Click</button>
<ChildComponent1 counter={counter} />
</div>
)
}
可以看到如果使用者按下 button 就會使 counter + 1,則 ChildComponent 就會把 counter 的值加上 times。
注意看到 ChildComponent
static getDerivedStateFromProps(props, state)
他是一個 static function 表示他沒有 this,也就不能存取任何 instance 的值。parameters 是 props、state。其中 props 是更新過後的 props,state 是本身 component state。
如果 state 有更改則必須回傳更改後的 state,不然就回傳 null。
Hooks 其實也可以達到同樣的功能
const ChildComponent1 = (props) => {
const [display, setDisplay] = useState(`${props.counter} times`);
useEffect(() => {
if (props.counter === 1) {
return undefined;
}
return setDisplay(`${props.counter} times`)
}, [props.counter])
return (
<h1>{display}</h1>
)
}
只要使用 useEffect 配合 dependency array 放置你要監聽的值即可(props.counter)。這樣就可以達到跟用 getDerivedStateFromProps 相同效果,並且程式碼更簡單更易閱讀。