一. class 組件創建方式
import React from 'react';
class B extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>hi</div>
)
}
}
二. Props 外部數據
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {name:'frank'}
}
onClick = ()=>{}
render(){
return <B name={this.state.name} onClick={this.onClick}>hi</B>
} // 這裏的name和onClick就是props,來源是從this.state來的,是從外部來的作爲props
}
// props如何初始化,這樣子做了之後this.props就是外部數據的對象地址了
class B extends React.Component {
constructor(props){
super(props);
}
render(){
}
}
// 讀取props
class B extends React.Component {
constructor(props){
super(props);
}
render(){
return <div onClick={this.props.onClick}>
{this.props.name}
<div>
{this.props.children}
</div>
</div>
}
}
// 不能去寫props,外部數據應該由外部更新
三. componentWillReceiveProps 的作用
- 接收外部數據,只能讀不能寫,外部呀數據由父組件傳遞
- 接受外部函數,在恰當的時機調用該函數,該函數一般是父組件的函數
import React from 'react';
class App extends React.Component {
constructor(props){
super(props)
this.state = {x : 1}
}
onClick = () => {
this.setState({
x: this.state.x + 1
})
}
render(){
return (
<div className="App">
App <button onClick={this.onClick}>+1</button>
<B name={this.state.x}/>
</div>
);
}
}
class B extends React.Component {
UNSAFE_componentWillReceiveProps(newProps, nextContext) {
console.log('舊的 props')
console.log(this.props)
console.log('props變化了')
console.log('新的p props')
console.log(newProps)
}
render(){
return (
<div>{this.props.name}</div>
)
}
}
export default App;
四. State & setState 內部數據
- 初始化 State
class B extends React.Component{
constructor(props){
super(props);
this.state = {
user: {name:'frank', age:187}
}
}
render(){
}
}
- setState 的兩種方式,推薦寫成函數的形式,一般就用第一個參數,還有第二個參數接受成功之後的回調函數,另外寫 state 的時候會進行一級合併(shallow merge)
onClick = () => {
this.setState({
x: this.state.x + 1
})
this.setState({
x: this.state.x + 1
})
}
onClick2 = () => {
this.setState((state)=>({x:state.x+1}))
this.setState((state)=>({x:state.x+1}))
}
五. 生命週期
let div = document.createElement('div')
// 這是div的 create/construct 過程
div.textContent = 'hi'
// 這是初始化state
document.body.appendChild(div)
// 這是div的mount過程
div.textContent = 'hi2'
// 這是div的update過程
div.remove()
// 這是div的unmount過程
函數列表,以下是常用的
constructor() - 這裏初始化state shouldComponentUpdate() - return false 阻止更新 render() - 創建虛擬DOM componentDidMount() - 組件已出現在頁面 componentDidUpdate() - 組件已更新 componentWillUnmount() - 組件將死
constructor的用途
初始化props
初始化state,但此時不能調用setState
用來寫bind this
constructor(){ this.onClick = this.onClick.bind(this) } 可以用新語法代替 onClick = ()=> {} constructor() { }
可不屑
shouldComponentUpdate的用途
- 返回true表示不阻止UI更新
- 返回false表示阻止UI更新
- 示例見下頁
- 面試常問: shouldComponentUpdate有什麼用?
- 答: 它允許我們手動判斷是否要進行組件更新,我們可以根據應用場景靈活地設置返回值,以避免不必要的更新
React.PureComponent會對state和props進行淺對比,就不需要shouldComponentUpdate了
render的用途
展示視圖,
// return 對應的對象是不是一個dom元素, 而是一個表示dom元素的對象, 我們稱其虛擬dom return (<div>...</div>)
只能有一個根元素
用React.Fragment做佔位,也可以寫成<></>,兩者等價
- 技巧
// render裏面可以寫if...else // 可以寫?: // 不能直接寫for,需要用數組 // 可以寫array.map
import React from 'react';
class App extends React.PureComponent { constructor(props){
super(props) this.state = { n:1 }
} onClick= ()=>{
this.setState(state=> ({ n: state.n+1 }))
}
render(){
console.log('render了一次') let message if(this.state.n % 2 === 0 ) { message = <div>偶數</div> } else { message = <span>奇數</span> } return ( <> {message} <button onClick={ this.onClick }>+1</button> </> )
} }
export default App; // 循環的寫法 render() { return this.state.array.map(n=>{n}) }
- componentDidMount()的用途 - 在元素插入頁面後執行代碼,這些代碼依賴DOM - 比如你想獲取div的高度,就最好在這裏寫 - 此處可以發起加載數據的AJAX請求(官方推薦) - 首次渲染會執行此鉤子
componentDidMount() { const div = document.getElementById('xxx') const {width} = div.getBoundingClientRect() // console.log(width) this.setState({width}) }
render(){
return( <div id='xxx'>Hello World, {this.state.width} </div> )
} ```
也可以用ref來做
import React from 'react'; class App extends React.PureComponent { constructor(props){ super(props) this.state = { n:1, width: undefined } this.divRef = React.createRef() } onClick= ()=>{ this.setState(state=> ({ n: state.n+1 })) } componentDidMount() { const div = this.divRef.current const {width} = div.getBoundingClientRect() // console.log(width) this.setState({width}) } render(){ return( <div ref={this.divRef}>Hello World, {this.state.width}px </div> ) } } export default App;
- 技巧
componentDidUpdate()的作用
- 在視圖更新後執行代碼
- 此處也可以發起AJAX請求,用於更新數據(看文檔)
- 首次渲染不會執行此鉤子
- 在此處setState可能會引起無限循環,除非放在if裏
- 若componentDidUpdate返回false,則不觸發此鉤子
- componentWillUnmount的用途
- 組件將要被移除頁面然後被銷燬時執行的代碼
- unmount過的組件不會再次mount
- 舉例:
如果你在componentDidMount裏面監聽了window scroll 那麼就要在componentWillUnmount的用途裏面取消監聽 如果你在componentDidMount裏面創建了Timer 那麼就要在componentWillUnmount裏面取消Timer 如果你在componentDidMount裏面創建了AJAX請求,這種情況比較特殊,數據還沒回來你就死了 那麼就要在componentWillUnmount裏面取消請求
總結:
- 能用函數組件就用函數組件,能用purecomponent就用purecomponent,最後不行採用 react.component
- 生命週期函數