React 原理詳解

1.setState() 說明

1.1 更新數據

setState() 是異步更新數據

可以多次調用 setState() ,隻會觸發一次重新渲染

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		// 異步更新數據
		this.setState({
			count: this.state.count + 1,
		})
        this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) // 1
	}
	render() {
		return (
			<div>
				<h1>計數器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

1.2 推薦語法

使用 setState((state,props)=>{}) 語法

state:表示最新的 state, props:表示最新的 props

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		/* // 異步更新數據
		this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) //1
    this.setState({
			count: this.state.count + 1,
		})
		console.log(this.state.count) //1
    */
		// 推薦語法
		this.setState((state, props) => {
			return {
				count: state.count + 1,
			}
		})
		this.setState((state, props) => {
			console.log('第二次調用:', state) //2
			return {
				count: state.count + 1,
			}
		})
		console.log(this.state.count) // 3
	}
	render() {
		return (
			<div>
				<h1>計數器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

1.3 第二個參數

  • 在狀態更新(頁面完成重新渲染)後立即執行某個操作
  • 語法:setState(updater[,callback])

callback 是指回調函數 可加可不加

import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 1,
	}
	handleClick = () => {
		this.setState(
			(state, props) => {
				return {
					count: state.count + 1,
				}
			},
			// 狀態更新後並且重新渲染後,立即執行
			() => {
				console.log('狀態更新完成:', this.state.count) // 2
				console.log(document.getElementById('title').innerText) // 計數器:2
				document.title = '更新後的 count 為:' + this.state.count
			}
		)
		console.log(this.state.count) //1
	}
	render() {
		return (
			<div>
				<h1 id='title'>計數器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

2.JSX 語法的轉化過程

  • JSX 僅僅是 createElement() 方法的語法糖(簡化語法)
  • JSX 語法被 @babel/preset-react 插件編譯為 createElement() 方法
  • React元素:是一個對象,用來描述你希望在屏幕上看到的內容

在這裡插入圖片描述

import React from 'react'
import ReactDOM from 'react-dom'
// JSX 語法的轉化過程
// const element = <h1 className='greeting'>Hello JSX</h1>
const element = React.createElement(
	'h1',
	{
		className: 'greeting',
	},
	'Hello JSX'
)
console.log(element)
ReactDOM.render(element, document.getElementById('root'))

3.組件更新機制

  • setState() 的兩個作用:1.修改 state 2.更新組件(UI)
  • 過程:父組件重新渲染是,也會重新渲染子組件,但隻會渲染當前組件子樹(當前組件及其所有子組件)

在這裡插入圖片描述

4.組件性能優化

4.1 減輕 state

  • 減輕 state :隻存儲跟組件渲染相關的數據(比如:count /列表數據/ loading 等)
  • 註意:不用渲染的書籍不要放在 state 中(比如定時器 id 等)
  • 需要在多個方法中用到的數據,應該放在 this 中

4.2 避免不必要的重新渲染

  • 組件更新機制:父組件更新會引起子組件也被更新
  • 問題:子組件沒有變化時也會被重新渲染,造成不必要的重新渲染
  • 解決方式:使用鉤子函數shouldComponentUpdate(nextProps,nextState)
  • 作用:通過返回值決定該組件是否重新渲染,返回 true 表示重新渲染, false 表示不重新渲染
  • 觸發時機:更新階段的鉤子函數,組件重新渲染前執行(shouldComponentUpdate -> render)
import React from 'react'
import ReactDOM from 'react-dom'
class Opp extends React.Component {
	state = {
		count: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				count: this.state.count + 1,
			}
		})
	}
	// 鉤子函數
	shouldComponentUpdate(nextProps, nextState) {
		// 返回 false,阻止組件重新渲染
		// return false
		// 最新的狀態
		console.log('最新的state', nextState)
		// 更新前的狀態
		console.log(this.state)
		// 返回 true,組件重新渲染
		return true
	}
	render() {
		console.log('組件更新瞭')
		return (
			<div>
				<h1>計數器:{this.state.count}</h1>
				<button onClick={this.handleClick}>+1</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

案例:隨機數

通過 nextState

import React from 'react'
import ReactDOM from 'react-dom'
// 生成隨機數
class Opp extends React.Component {
	state = {
		number: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				number: Math.floor(Math.random() * 3),
			}
		})
	}
	// 兩次生成的隨機數可能相同,則沒必要重新渲染
	shouldComponentUpdate(nextState) {
		console.log('最新狀態:', nextState, '當前狀態:', this.state)
		return nextState.number !== this.state.number
		/* if ( nextState.number !== this.state.number) {
			return true
		}
		return false*/
	}
	render() {
		console.log('render')
		return (
			<div>
				<h1>隨機數:{this.state.number}</h1>
				<button onClick={this.handleClick}>重新生成</button>
			</div>
		)
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

通過 nextState

import React from 'react'
import ReactDOM from 'react-dom'
// 生成隨機數
class Opp extends React.Component {
	state = {
		number: 0,
	}
	handleClick = () => {
		this.setState((state) => {
			return {
				number: Math.floor(Math.random() * 3),
			}
		})
	}
	render() {
		return (
			<div>
				<NumberBox number={this.state.number} />
				<button onClick={this.handleClick}>重新生成</button>
			</div>
		)
	}
}
class NumberBox extends React.Component {
	shouldComponentUpdate(nextProps) {
		console.log('最新props:', nextProps, '當前props:', this.props)
		return nextProps.number !== this.props.number
	}
	render() {
		console.log('子組件render')
		return <h1>隨機數:{this.props.number}</h1>
	}
}
ReactDOM.render(<Opp />, document.getElementById('root'))

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: