這篇文章主要介紹“react hook和class的區(qū)別是什么”,在日常操作中,相信很多人在react hook和class的區(qū)別是什么問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”react hook和class的區(qū)別是什么”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

成都做網(wǎng)站、成都網(wǎng)站建設(shè)介紹好的網(wǎng)站是理念、設(shè)計(jì)和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)公司擁有的網(wǎng)站設(shè)計(jì)理念、多方位的設(shè)計(jì)風(fēng)格、經(jīng)驗(yàn)豐富的設(shè)計(jì)團(tuán)隊(duì)。提供PC端+手機(jī)端網(wǎng)站建設(shè),用營銷思維進(jìn)行網(wǎng)站設(shè)計(jì)、采用先進(jìn)技術(shù)開源代碼、注重用戶體驗(yàn)與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。
區(qū)別:1、hooks的寫法比class簡(jiǎn)潔;2、hooks的業(yè)務(wù)代碼比class更加聚合;3、class組件的邏輯復(fù)用通常用render props以及HOC兩種方式,而react hooks提供了自定義hooks來復(fù)用邏輯。
本教程操作環(huán)境:Windows7系統(tǒng)、react17.0.1版、Dell G3電腦。
react hooks與class組件有哪些區(qū)別?下面就來帶大家對(duì)比一下react hooks和class組件,聊聊它們的區(qū)別。
函數(shù)組件中不能擁有自己的狀態(tài)(state)。在hooks之前函數(shù)組件是無狀態(tài)的,都是通過props來獲取父組件的狀態(tài),但是hooks提供了useState來維護(hù)函數(shù)組件內(nèi)部的狀態(tài)。
函數(shù)組件中不能監(jiān)聽組件的生命周期。useEffect聚合了多個(gè)生命周期函數(shù)。
class組件中生命周期較為復(fù)雜(在15版本到16版本的變化大)。
class組件邏輯難以復(fù)用(HOC,render props)。
我們以最簡(jiǎn)單的計(jì)數(shù)器為例:
class組件
class ExampleOfClass extends Component {
constructor(props) {
super(props)
this.state = {
count: 1
}
}
handleClick = () => {
let { count } = this.state
this.setState({
count: count+1
})
}
render() {
const { count } = this.state
return (
<div>
<p>you click { count }</p>
<button onClick={this.handleClick}>點(diǎn)擊</button>
</div>
)
}
}hooks
function ExampleOfHooks() {
const [count, setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
}
return (
<div>
<p>you click { count }</p>
<button onClick={handleClick}>點(diǎn)擊</button>
</div>
)
}可以看到使用hooks的代碼相比class組件代碼更加的簡(jiǎn)潔、清晰。
使用class組件經(jīng)常會(huì)出現(xiàn)一個(gè)功能出現(xiàn)在兩個(gè)生命周期函數(shù)內(nèi)的情況,這樣分開寫有時(shí)候可能會(huì)忘記。比如:
let timer = null
componentDidMount() {
timer = setInterval(() => {
// ...
}, 1000)
}
// ...
componentWillUnmount() {
if (timer) clearInterval(timer)
}由于添加定時(shí)器和清除定時(shí)器是在兩個(gè)不同的生命周期函數(shù),中間可能會(huì)有很多其他的業(yè)務(wù)代碼,所以可能會(huì)忘記清除定時(shí)器,如果在組件卸載時(shí)沒有添加清楚定時(shí)器的函數(shù)就可能會(huì)造成內(nèi)存泄漏、網(wǎng)絡(luò)一直請(qǐng)求等問題。
但是使用hooks可以讓代碼更加的集中,方便我們管理,也不容易忘記:
useEffect(() => {
let timer = setInterval(() => {
// ...
}, 1000)
return () => {
if (timer) clearInterval(timer)
}
}, [//...])class組件的邏輯復(fù)用通常用render props以及HOC兩種方式。react hooks提供了自定義hooks來復(fù)用邏輯。
下面以獲取鼠標(biāo)在頁面的位置的邏輯復(fù)用為例:
class組件render props方式復(fù)用
import React, { Component } from 'react'
class MousePosition extends Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
}
}
handleMouseMove = (e) => {
const { clientX, clientY } = e
this.setState({
x: clientX,
y: clientY
})
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove)
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
const { children } = this.props
const { x, y } = this.state
return(
<div>
{
children({x, y})
}
</div>
)
}
}
// 使用
class Index extends Component {
constructor(props) {
super(props)
}
render() {
return (
<MousePosition>
{
({x, y}) => {
return (
<div>
<p>x:{x}, y: {y}</p>
</div>
)
}
}
</MousePosition>
)
}
}
export default Index自定義hooks方式復(fù)用
import React, { useEffect, useState } from 'react'
function usePosition() {
const [x, setX] = useState(0)
const [y, setY] = useState(0)
const handleMouseMove = (e) => {
const { clientX, clientY } = e
setX(clientX)
setY(clientY)
}
useEffect(() => {
document.addEventListener('mousemove', handleMouseMove)
return () => {
document.removeEventListener('mousemove', handleMouseMove)
}
})
return [
{x, y}
]
}
// 使用
function Index() {
const [position] = usePosition()
return(
<div>
<p>x:{position.x},y:{position.y}</p>
</div>
)
}
export default Index可以很明顯的看出使用hooks對(duì)邏輯復(fù)用更加的方便,使用的時(shí)候邏輯也更加清晰。
語法
const [value, setValue] = useState(0)
這種語法方式是ES6的數(shù)組結(jié)構(gòu),數(shù)組的第一個(gè)值是聲明的狀態(tài),第二個(gè)值是狀態(tài)的改變函數(shù)。
每一幀都有獨(dú)立的狀態(tài)
個(gè)人理解針對(duì)每一幀獨(dú)立的狀態(tài)是采用了閉包的方法來實(shí)現(xiàn)的。
function Example() {
const [val, setVal] = useState(0)
const timeoutFn = () => {
setTimeout(() => {
// 取得的值是點(diǎn)擊按鈕的狀態(tài),不是最新的狀態(tài)
console.log(val)
}, 1000)
}
return (
<>
<p>{val}</p>
<button onClick={()=>setVal(val+1)}>+</button>
<button onClick={timeoutFn}>alertNumber</button>
</>
)
}當(dāng)組件的狀態(tài)或者props更新時(shí),該函數(shù)組件會(huì)被重新調(diào)用渲染,并且每一次的渲染都是獨(dú)立的都有自己獨(dú)立的props以及state,不會(huì)影響其他的渲染。
語法
useEffect(() => {
//handler function...
return () => {
// clean side effect
}
}, [//dep...])useEffect接收一個(gè)回調(diào)函數(shù)以及依賴項(xiàng),當(dāng)依賴項(xiàng)發(fā)生變化時(shí)才會(huì)執(zhí)行里面的回調(diào)函數(shù)。useEffect類似于class組件didMount、didUpdate、willUnmount的生命周期函數(shù)。
注意點(diǎn)
useEffect是異步的在組件渲染完成后才會(huì)執(zhí)行
useEffect的回調(diào)函數(shù)只能返回一個(gè)清除副作用的處理函數(shù)或者不返回
如果useEffect傳入的依賴項(xiàng)是空數(shù)組那么useEffect內(nèi)部的函數(shù)只會(huì)執(zhí)行一次
useMemo和useCallback主要用于減少組件的更新次數(shù)、優(yōu)化組件性能的。
useMemo接收一個(gè)回調(diào)函數(shù)以及依賴項(xiàng),只有依賴項(xiàng)變化時(shí)才會(huì)重新執(zhí)行回調(diào)函數(shù)。
useCallback接收一個(gè)回調(diào)函數(shù)以及依賴項(xiàng),并且返回該回調(diào)函數(shù)的memorize版本,只有在依賴項(xiàng)重新變化時(shí)才會(huì)重新新的memorize版本。
語法
const memoDate = useMemo(() => data, [//dep...])
const memoCb = useCallback(() => {//...}, [//dep...])在優(yōu)化組件性能時(shí)針對(duì)class組件我們一般使用React.PureComponent,PureComponent會(huì)在shouldUpdate進(jìn)行一次錢比較,判斷是否需要更新;針對(duì)函數(shù)組件我們一般使用React.memo。但是在使用react hooks時(shí)由于每一次渲染更新都是獨(dú)立的(生成了新的狀態(tài)),即使使用了React.memo,也還是會(huì)重新渲染。
比如下面這種場(chǎng)景,改變子組件的name值后由于父組件更新后每次都會(huì)生成新值(addAge函數(shù)會(huì)改變),所以子組件也會(huì)重新渲染。
function Parent() {
const [name, setName] = useState('cc')
const [age, setAge] = useState(22)
const addAge = () => {
setAge(age + 1)
}
return (
<>
<p>父組件</p>
<input value={name} onChange={(e) => setName(e.target.value)} />
<p>age: {age}</p>
<p>-------------------------</p>
<Child addAge={addAge} />
</>
)
}
const Child = memo((props) => {
const { addAge } = props
console.log('child component update')
return (
<>
<p>子組件</p>
<button onClick={addAge}>click</button>
</>
)
})使用useCallback優(yōu)化
function Parent() {
const [name, setName] = useState('cc')
const [age, setAge] = useState(22)
const addAge = useCallback(() => {
setAge(age + 1)
}, [age])
return (
<>
<p>父組件</p>
<input value={name} onChange={(e) => setName(e.target.value)} />
<p>age: {age}</p>
<p>-------------------------</p>
<Child addAge={addAge} />
</>
)
}
const Child = memo((props) => {
const { addAge } = props
console.log('child component update')
return (
<>
<p>子組件</p>
<button onClick={addAge}>click</button>
</>
)
})只有useCallback的依賴性發(fā)生變化時(shí),才會(huì)重新生成memorize函數(shù)。所以當(dāng)改變name的狀態(tài)是addAge不會(huì)變化。
useRef類似于react.createRef。
const node = useRef(initRef)
useRef 返回一個(gè)可變的 ref 對(duì)象,其 current 屬性被初始化為傳入的參數(shù)(initRef)
作用在DOM上
const node = useRef(null)
<input ref={node} />這樣可以通過node.current屬性訪問到該DOM元素。
需要注意的是useRef創(chuàng)建的對(duì)象在組件的整個(gè)生命周期內(nèi)保持不變,也就是說每次重新渲染函數(shù)組件時(shí),返回的ref 對(duì)象都是同一個(gè)(使用 React.createRef ,每次重新渲染組件都會(huì)重新創(chuàng)建 ref)。
useReducer類似于redux中的reducer。
語法
const [state, dispatch] = useReducer(reducer, initstate)
useReducer傳入一個(gè)計(jì)算函數(shù)和初始化state,類似于redux。通過返回的state我們可以訪問狀態(tài),通過dispatch可以對(duì)狀態(tài)作修改。
const initstate = 0;
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {number: state.number + 1};
case 'decrement':
return {number: state.number - 1};
default:
throw new Error();
}
}
function Counter(){
const [state, dispatch] = useReducer(reducer, initstate);
return (
<>
Count: {state.number}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
)
}通過useContext我們可以更加方便的獲取上層組件提供的context。
父組件
import React, { createContext, Children } from 'react'
import Child from './child'
export const MyContext = createContext()
export default function Parent() {
return (
<div>
<p>Parent</p>
<MyContext.Provider value={{name: 'cc', age: 21}}>
<Child />
</MyContext.Provider>
</div>
)
}子組件
import React, { useContext } from 'react'
import { MyContext } from './parent'
export default function Parent() {
const data = useContext(MyContext) // 獲取父組件提供的context
console.log(data)
return (
<div>
<p>Child</p>
</div>
)
}使用步驟
父組件創(chuàng)建并導(dǎo)出context:export const MyContext = createContext()
父組件使用provider和value提供值:<MyContext.provide value={{name: 'cc', age: 22}} />
子組件導(dǎo)入父組件的context:import { MyContext } from './parent'
獲取父組件提供的值:const data = useContext(MyContext)
不過在多數(shù)情況下我們都不建議使用context,因?yàn)闀?huì)增加組件的耦合性。
useEffect 在全部渲染完畢后才會(huì)執(zhí)行;useLayoutEffect 會(huì)在 瀏覽器 layout之后,painting之前執(zhí)行,并且會(huì)柱塞DOM;可以使用它來讀取 DOM 布局并同步觸發(fā)重渲染。
export default function LayoutEffect() {
const [color, setColor] = useState('red')
useLayoutEffect(() => {
alert(color) // 會(huì)阻塞DOM的渲染
});
useEffect(() => {
alert(color) // 不會(huì)阻塞
})
return (
<>
<div id="myDiv" style={{ background: color }}>顏色</div>
<button onClick={() => setColor('red')}>紅</button>
<button onClick={() => setColor('yellow')}>黃</button>
</>
)
}上面的例子中useLayoutEffect會(huì)在painting之前執(zhí)行,useEffect在painting之后執(zhí)行。
hooks讓函數(shù)組件擁有了內(nèi)部狀態(tài)、生命周期,使用hooks讓代碼更加的簡(jiǎn)介,自定義hooks方便了對(duì)邏輯的復(fù)用,并且擺脫了class組件的this問題;但是在使用hooks時(shí)會(huì)產(chǎn)生一些閉包問題,需要仔細(xì)使用。
到此,關(guān)于“react hook和class的區(qū)別是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
文章題目:reacthook和class的區(qū)別是什么
URL網(wǎng)址:http://www.chinadenli.net/article36/pgshsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、企業(yè)建站、搜索引擎優(yōu)化、響應(yīng)式網(wǎng)站、網(wǎng)站排名、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)