用getDerivedStateFromProps代替componentWillReceiveProps

Why

在React 16.3版本中,React官方推出了新的生命週期方法,而有一部分舊的生命週期方法則被標記為Unsafe,該方法在React17中將會被廢棄,而今日的主角componentWillReceiveProps則是其中一個。

componentWillReceiveProps

先來看看componentWillReceiveProps是怎麼用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import * as React from "react";
import * as ReactDOM from "react-dom";

interface IInputProps {
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
}

interface IInputState {
value: string;
}

class Input extends React.Component<IInputProps, IInputState> {
public constructor(props: IInputProps) {
super(props);

const initialValue = props.value
? props.value
: props.defaultValue
? props.defaultValue
: "";

this.state = {
value: initialValue
};
}

public UNSAFE_componentWillReceiveProps(nextProps: IInputProps) {
if (nextProps.value !== undefined && nextProps.value !== this.props.value) {
this.setState({ value: nextProps.value });
}
}

handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { onChange } = this.props;
if (onChange) {
// 受控
onChange(e.target.value);
} else {
this.setState({ value: e.target.value });
}
};

public render(): React.ReactNode {
const { value } = this.state;
return <input value={value} onChange={this.handleChange} />;
}
}

const App = () => {
const [value, setValue] = React.useState();
return (
<>
<Input
value={value}
onChange={value => {
setValue(value);
}}
/>
</>
);
};

ReactDOM.render(<App />, document.getElementById("root"));

getDerivedStateFromProps

getDerivedStateFromPropscomponentWilLReceiveProps最大的不同就是前者靜態(static),後者是類方法,也就是getDerivedStateFromProps不能訪問this。第二個不同是調用的次數和時機。

看看這個React15版本的生命週期圖。

再看看這個React16版本比較比較。

在React15中,componentWilLReceiveProps只會在更新(Updating)的時候調用,而React16的getDerivedStateFromProps在掛載(Mounting)和更新(Updating)時都會調用,因此轉換要需要注意添加處理掛載時的邏輯。

開始轉換

可以看到在掛載時, componentWilLReceiveProps並沒有被調用,在輸入的時候(Input的input -> handleChange -> props.onChange -> App的setValue -> App的value改變 -> Input更新),componentWillReceiveProps被調用一次。

componentWilLReceiveProps替換為getDerivedStateFromProps

1
2
3
4
5
6
7
8
9
10
11
12
static getDerivedStateFromProps(
nextProps: IInputProps,
prevState: IInputState
) {
if (nextProps.value !== undefined && nextProps.value !== prevState.value) {
return {
value: nextProps.value
};
} else {
return null;
}
}

在第一次掛載的時候,getDerivedStateFromProps就已經被調用了一次,這時prevState就是construtor裡設置的。

在替換成getDerivedStateFromProps的時候,需要注意週用時機和次數即可。

# React
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×