React 函式元件
阿新 • • 發佈:2021-11-26
如何建立函式元件
- 箭頭函式形式
const Hello = (props) => { return <div>{props.message}</div> }
// 可以簡寫成
const Hello = props => <div>{props.message}</div>
- function 形式
function Hello(props) {
return <div>{props.message}</div>
}
函式元件 比 class元件 程式碼量少
看看這個例子,同樣實現+1
class 元件
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
n: 1
}
}
click = () => {
this.setState(state => ({
n: state.n + 1
}))
}
render() {
return (
<div>
{this.state.n}
<button onClick={this.click}>+1</button>
</div>
)
}
}
函式元件
const App = props => {
const [n, setN] = useState(0)
const click = () => {
setN(n + 1)
}
return (
<div>
{n}
<button onClick={click}>+1</button>
</div>
)
}
看來函式元件真的有很大的優勢
可以用函式元件代替 class 元件嗎?
面臨兩個問題
- 函式元件沒有 state
- 函式元件沒有生命週期
沒有 State 怎麼辦?
React v16.8.0 推出 Hooks API,其中的一個 API 叫做 useState 可解決問題
import React, { useState } from 'react';
function Example() {
// 宣告一個叫 "count" 的 state 變數
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
沒有生命週期怎麼辦?
React v16.8.0 推出 Hooks API,其中的一個 API 叫做 useEffect 可解決問題
- 模擬 componentDidMount
useEffect(()=> { console.log('第一次渲染') }, [])
// 第個引數是 [] 時,函式只在開始時執行一次
useEffect 的第二個引數是需要監聽的state
屬性,如果省略代表監聽所有state
屬性的變化,如果是空,則代表不監聽任何state
屬性
如果指定了需要監聽的state
物件,那麼就只會監聽這一個state
屬性。其他屬性的變化,不會觸發函式的執行
- 模擬 componentDidUpdate
useEffect(() => { console.log('任意屬性變更') })
useEffect(()=> { console.log('n變了') }, [n])
// 不傳入第二個引數時,監聽全部屬性
// 傳入 [n] 時,只監聽 n
但是這樣並不能真正模擬 componentDidUpdate,因為它不會在第一次渲染時執行,而上面的程式碼無法做到這一點
所以為了修改這個問題,我們需要增加一些程式碼
const [nUpdateCount, setNUpdateCount] = useState(0)
useEffect(() => {
setNUpdateCount(nUpdateCount => nUpdateCount + 1)
}, [n])
useEffect(() => {
if (nUpdateCount > 1) {
console.log('更新了一次')
}
}, [nUpdateCount])
我們可以通過nUpdateCount
來解決這個問題,nUpdateCount
檢測到n
的第一次變化,重0
變為1
,而useEffect
中判斷nUpdateCount
大於1
時,才開始執行
但是這樣的程式碼似乎還是有點繁瑣,還可以繼續優化
寫成一個useUpdate
函式,fn
是更新時執行的函式,dey
是監聽物件,這個函式可以從元件中提取處理,使用時直接應用
const useUpdate = (fn, dey) => {
const [count, setCount] = useState(0)
useEffect(() => {
setCount(count => count + 1)
}, [dey])
useEffect(() => {
if (count > 1) {fn()}
}, [count, fn])
}
元件中直接呼叫useUpdate
useUpdate(() => {console.log('更新了一次')}, n)
- 模擬 componmentWillUnmount
useEffect(() => {
console.log('資料更新了')
return () => {
console.log("我要被銷燬了")
}
})
useEffect可以再返回一個函式,他會在元件消失時呼叫,而console.log(
'資料更新了')
則會在元件發生變化重渲染時呼叫
- 模擬 shouldComponentUpdate
const MyComponent = React.memo(
_MyComponent,
(prevProps, nextProps) => nextProps.count !== prevProps.count
)
React.memo 包裹一個元件來對它的 props 進行淺比較,但這不是一個 hooks,因為它的寫法和 hooks 不同,其實React.memo 等效於 PureComponent,但它只比較 props。