1. JSX
JSX是Javascript的語法擴充,在React中通過JSX渲染元素
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
複製程式碼
類似模版渲染,jsx可以通過變數來定義,然後在React中渲染。
在jsx中定義一些屬性是使用的小駝峰的寫法,如className,tabIndex
Babel 會把 JSX 轉譯成一個名為 React.createElement() 函式呼叫。
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
複製程式碼
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
複製程式碼
所以事實上jsx還是 React.createElement(component, props, ...children) 的語法糖。
2. React元素渲染
React中通過 ReactDOM.render 的方式渲染元素,配合上強大的jsx語法,一切皆為變數,一切在 {} 的變數都能被渲染。
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {newDate().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
複製程式碼
3. React生命週期
- constructor()
執行建構函式
- render()
渲染
- componentDidMount()
在Dom樹渲染完成後立即呼叫componentDidMount()。需要DOM節點的初始化應該放在這裡。如果需要從遠端端點載入資料,這是例項化網路請求的好地方。
如果使用DidMount 記得要在元件使用之後取消訂閱,componentWillUnmount
- shouldComponentUpdate() (比較少用)
當元件接收到新屬性,或者元件的狀態發生改變時觸發。元件首次渲染時並不會觸發
shouldComponentUpdate(newProps, newState) {
if (newProps.number < 5) return true;
return false
}
//該鉤子函式可以接收到兩個引數,新的屬性和狀態,返回true/false來控制元件是否需要更新。
複製程式碼
一般我們通過該函式來優化效能:一個React專案需要更新一個小元件時,很可能需要父元件更新自己的狀態。而一個父元件的重新更新會造成它旗下所有的子元件重新執行render()方法,形成新的虛擬DOM,再用diff演算法對新舊虛擬DOM進行結構和屬性的比較,決定元件是否需要重新渲染.無疑這樣的操作會造成很多的效能浪費,所以我們開發者可以根據專案的業務邏輯,在shouldComponentUpdate()中加入條件判斷,從而優化效能
- componentDidUpdate()
元件更新
componentDidUpdate(prevProps, prevState, snapshot)
更新發生後立即呼叫componentDidUpdate()初始渲染不會呼叫此方法。
將此作為在更新元件時對DOM進行操作的機會。只要將當前props與之前的props進行比較(例如,如果props未更改,則可能不需要網路請求),這也是進行網路請求的好地方。
componentDidUpdate(prevProps) {
// 不要忘了比較props的狀態
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
複製程式碼
- componentWillUnmount()
元件解除安裝
在解除安裝和銷燬元件之前立即調componentWillUnmount()在此方法中執行任何必要的清理,例如使計時器無效,取消網路請求或清除在componentDidMount()中建立的任何訂閱。
- componentDidCatch()
在渲染期間,生命週期方法或任何子元件的建構函式中發生錯誤時,將呼叫這些方法。
import React from 'react'
import ReactDOM from 'react-dom';
class SubCounter extends React.Component {
// 在17版本將要廢棄,還是不用較好
componentWillReceiveProps() {
console.log('9、子元件將要接收到新屬性');
}
shouldComponentUpdate(newProps, newState) {
console.log('10、子元件是否需要更新');
if (newProps.number < 5) return true;
return false
}
// 同17版本將要廢棄
componentWillUpdate() {
console.log('11、子元件將要更新');
}
componentDidUpdate() {
console.log('13、子元件更新完成');
}
componentWillUnmount() {
console.log('14、子元件將解除安裝');
}
render() {
console.log('12、子元件掛載中');
return (
<p>{this.props.number}</p>
)
}
}
// 父元件
class Counter extends React.Component {
static defaultProps = {
//1、載入預設屬性
name: 'sls',
age:23
};
constructor() {
super();
//2、載入預設狀態
this.state = {number: 0}
}
// 新版本已經廢棄
componentWillMount() {
console.log('3、父元件掛載之前');
}
componentDidMount() {
console.log('5、父元件掛載完成');
}
shouldComponentUpdate(newProps, newState) {
console.log('6、父元件是否需要更新');
if (newState.number<15) return true;
return false
}
// 新版本已經廢棄
componentWillUpdate() {
console.log('7、父元件將要更新');
}
componentDidUpdate() {
console.log('8、父元件更新完成');
}
handleClick = () => {
this.setState({
number: this.state.number + 1
})
};
render() {
console.log('4、render(父元件掛載)');
return (
<div>
<p>{this.state.number}</p>
<button onClick={this.handleClick}>+</button>
{this.state.number<10?<SubCounter number={this.state.number}/>:null}
</div>
)
}
}
ReactDOM.render(<Counter/>, document.getElementById('root'));
複製程式碼
最後附上生命週期圖示
參考連結 React生命週期