1. 程式人生 > 其它 >React 函式元件

React 函式元件

如何建立函式元件

  • 箭頭函式形式
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。