1. 場景描述
在做個人項目的時候, 發現了一個問題: ant design UI 框架中, Select 組件的 defaultValue 屬性失效了, 即設置了defaultValue 值缺沒有默認的選定內容;
上面這個問題可以抽象成為如下沙盒:
PS: 該沙盒最好在codesandbox 網站下運行
import React from "react";
import { Select } from 'antd';
const { Option } = Select;
import 'antd/dist/antd.css'
const log = console.log.bind(console)
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
}
}
// 1. 當生命周期函數為componentDidMount 時, 執行的順序應該為:
// constructor -> render -> componentDidMount -> render;
// 而控制台顯示執行了4次render, 這是為什么?
// 2. 當生命周期函數為componentDidMount 時, 在最后一次執行render時,
// defaultValue 屬性已經被賦值為here, 為什么這個屬性沒有效果
// componentDidMount() {
// this.setState({
// defaultValue: 'here'
// })
// }
// 3. 當生命周期函數為componentWillMount 時, 執行的順序為:
// constructor -> componentWillMount -> render(加載過程默認的)-> render(this.setData 更新過程觸發的);
// 那么為什么兩次控制台輸出都是here, 這是由於consolo.log 的限制造成的嗎?
// componentWillMount() {
// this.setState({
// defaultValue: 'here'
// })
// }
render() {
let {defaultValue} = this.state
log('執行了render 函數 defaultValue = ', String(defaultValue))
return (
<>
<Select value={defaultValue} style={{ width: 120 }}>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
<Option value="here">
here
</Option>
<Option value="Yiminghe">yiminghe</Option>
</Select>
</>
)
}
}
export default App
2. 問題描述即解答
2.1 組件渲染兩次?
當生命周期函數為componentDidMount 時, 執行的順序應該為: constructor -> render -> componentDidMount -> render; 而控制台顯示執行了4次render, 這是為什么?
運行結果:
上面的沙盒(demo)運行環境為: codesandbox, 如果是在本地自建React 項目, 將不會運行4次, 而應該是2次
因為 React 在 Dev mode 下會刻意執行兩次渲染,以防止組件內有什么 side effect 引起 bug,提前預防; 詳細內容可以參見如下地址: 為什么 react 的函數組件每次渲染執行兩次?
2.2 ant design Select defaultValue 屬性失效
當生命周期函數為componentDidMount 時, 在最后一次執行render時, defaultValue 屬性已經被賦值為here, 為什么這個屬性沒有效果
因為組件第一次加載的時候會取defaultValue,之后重新渲染將不會處理defaultValue。如果重新渲染組件時, 還需要加載默認值, 則使用value 屬性; 詳細內容可以參見如下地址: ant design Select API
其實這個嚴格上來說是自己沒有好好看文檔, 先入為主了.
2.3 componentWillMount 生命周期
當生命周期函數為componentWillMount 時, 執行的順序為: constructor -> componentWillMount -> render(加載過程默認的)-> render(this.setData 更新過程觸發的);那么為什么兩次控制台輸出都是here, 這是由於consolo.log 的限制造成的嗎?
首先輸出兩次的原因是因為組件渲染了兩次, 這個可以參考第一個問題;
當生命周期函數為componentWillMount 時, 如果在componentWillMount 生命周期中使用this.setData, 此時this.setData 是一個同步函數, 而非異步函數, 因此render 中defaultValue 的值為 here
值得說明的是 componentWillMount 該生命周期函數已不被官方所推薦, 因此盡量不要使用. 具體內容可以參考如下地址: React 官方文檔
this.props 數據應該只在子組件負責渲染; this.props 數據更改應該發生在父組件, 這樣更符合生命周期設計(componentWillReceiveProps生命周期方法已不被官方推薦