React面試題整理
1、react的生命周期
1)、生命周期是什么?
react 實例的生命周期,就是react實例從初始化,更新,到銷毀的過程
2)、react實例生命周期經歷三個階段
初始化階段:完成從react組件創建到首次渲染的過程
更新階段:當調用setState函數時,會引起組件的重新渲染
銷毀階段:完成組件的銷毀
3)、三個階段分別對應的構造函數有:
- 初始化階段:
constructor
構造函數里,可以做狀態的初始化,接收props的傳值
componentWillMount: 在渲染前調用,相當於vue中的beforeMount
render
渲染函數,不要在這里修改數據。 vue中也有render函數。
componentDidMount
渲染完畢,在第一次渲染后調用。
- 運行中階段(更新)
當組件的 props 或 state 發生變化時會觸發更新(嚴謹的說,是只要調用了setState()或者改變了props時)。組件更新的生命周期調用順序如下:
shouldComponentUpdate
是否更新? 需要返回true或者false。如果是false,那么組件就不會繼續更新了。
componentWillUpdate,
即將更新。
componentWillReceiveProps(nextProps): 在組件接收到一個新的 prop (更新后)時被調用。這個方法在初始化render時不會被調用。nextProps 是props的新值,而 this.props是舊值。
render
不要在這里修改數據
componentDidUpdate
在組件完成更新后立即調用。在初始化時不會被調用。 相當於vue中的updated
- 銷毀階段(卸載)
componentWillUnmount()
即將卸載,可以做一些組件相關的清理工作,例如取消計時器、網絡請求等
2、為什么虛擬DOM 會提高性能
首先,(虛擬DOM是什么) 虛擬DOM就是一個JavaScript對象。通過這個JavaScript對象來描述真實DOM
如:
{
tagName:"p",
style:"width:200px;height: 100px;",
innerHTML:"我是p"
},
其次,操作虛擬DOM,就是在操作javascript對象,所以,並不會引起頁面的重繪和重排。而操作真實DOM是會引起頁面的重繪和重排的。
https://blog.csdn.net/jiang7701037/article/details/98516468 (頁面的重排和回流)
3、React的diff原理
-
傳統diff算法
需要遍歷整棵樹的節點然后進行比較,是一個深度遞歸的過程,運算復雜度常常是O(n^3) -
react diff的優化策略
-
DOM節點跨層級的操作不做優化,因為很少這么做,這是針對的tree層級的策略;
-
對於同一個類的組件,會生成相似的樹形結構,對於不同類的組件,生成不同的樹形結構,這是針對conponent層級的策略;
-
對於同一級的子節點,擁有同層唯一的key值,來做刪除、插入、移動的操作,這是針對element層級的策略;
4、調用setState之后,發生了什么?
1)、合並state
把傳入setState()里的參數對象和當前的state進行(屬性)合並。 觸發調和過程(Reconciliation)
2)、 重新渲染組件
2.1) React 會以相對高效的方式根據新的狀態構建 React 元素樹並且着手重新渲染整個 UI 界面;
2.2) React 會自動計算出新的樹與老樹的節點差異(用diff算法),然后根據差異對界面進行最小化重渲染
5、state和props的區別
1)、state是組件的狀態,也叫組件內部的數據
2)、props是組件的屬性,也可以認為是外部給組件傳入的數據
6、在構造函數里調用super函數並把props作為參數傳入的作用是啥?
1)、在構造函數里調用super的目的是:保證子類(組件里)有this;
在ES6中,super()函數就是父類的構造函數。所以,在react里定義類組件時,調用super就是在調用React.Component的構造函數。
2)、調用super函數時,把props傳入的目的是,保證this有屬性props;即:在子類(組件)里能夠使用this.props。
即: 執行 super(props) 是為了讓 React.Component 初始化 this.props。
React.Component類內部寫法:
class Component {
constructor(props) {
this.props = props;
}
}
3)、補充解釋:
看代碼(很奇怪的現象):
class Home extends React.Component{
constructor(props){
super();//此處沒有props
}
render(){
return (
{/*下面竟然可以拿到 this.props*/}
<div>{this.props.name}</div>
)
}
}
ReactDOM.render(<Home name="hi"/>,document.getElementById("box"))
為什么會出現以上情況?
因為,React組件(如:上面的Home組件)在實例化時, 會設置一遍 props 。所以,沒有問題嘍。
那,那,那……??@#¥……&!*…… 天哪?
再看:
class Home extends React.Component{
constructor(props){
super();//此處沒有props
console.log(this.props);//這個是undefined。請在super里傳遞props,試試
}
render(){
return (
<div>{this.props.name}</div>
)
}
}
ReactDOM.render(<Home name="hi"/>,document.getElementById("box"))
所以:
組件的super里如果不傳遞props
1)、可以在其它函數里使用this.props,因為,組件的構造函數會再次設置props的
2)、在構造函數里,this.props是undefined。即:this.props.屬性名會報錯。因為,React.Component的構造函數沒有增加props屬性。
7、為什么建議傳遞給setState函數的參數是回調函數而不是對象?
因為,this.setState()函數內部是異步執行的。
1)、如果給setState()的參數寫成對象的話,你會誤以為它是同步的。進而,如果想使用新的值,就會下意識調用setState完畢后,直接使用新的msg的值,
如下代碼,你是否會下意識(“直觀”)地覺得是異步呢,哈哈
this.setState({
msg:"hello"
});
console.log(this.state.msg);// 親,這個值不是hello
2)、如果寫成回調函數的話,你就不會有以上的誤解。
如下代碼:
//改變狀態前后都想做一些事情:
this.setState((prevState)=>{
// prevState:是舊值
console.log("prevState",prevState)
return {
age:15
}
},()=>{
// this.state:就是新值。
console.log(this.state.age);
});
8、React中的setState是同步執行還是異步執行?如果是異步的?怎么拿到執行后的state?
setState是異步的。
如果要拿到修改后的狀態,需要使用回調函數的方式,如下:
//改變狀態后想做一些事情:
this.setState({
屬性名:屬性值
}, () => {
//一般是用於在setState之后做一些操作
//this.state == 修改之后的state
})
9、為什么不能直接用以下辦法更新state
this.state.msg = “hello”;
因為,這樣不會引起組件的重新渲染,所以,數據修改后沒法 呈現在頁面上。
而調用setState()函數,會引起組件的重新渲染,這樣更新的數據就會呈現在頁面上。