1. 程式人生 > 其它 >React Hooks 學習 - 04 自定義Hook、路由鉤子函式

React Hooks 學習 - 04 自定義Hook、路由鉤子函式

自定義 Hook 函式

自定義 Hook 是標準的封裝和共享邏輯的方式,其實就是邏輯和內建 Hook 的組合,用於將元件邏輯提取到可重用的函式中

自定義 Hook 是一個函式,其名稱以 use 開頭,函式內部可以呼叫其它的 Hook。

使用自定義 Hook 提取可複用的邏輯,相比 render props高階函式簡單很多。

示例1

初始示例

import { useState, useEffect, useRef} from 'react'

function App() {
  const [count, setCount] = useState(0)
  const timerId =
useRef() useEffect(() => { timerId.current = setInterval(() => { setCount(count => count + 1) }, 1000) return () => { clearInterval(timerId.current) } }, []) return ( <div> <div>Count 的值:{count}</div> <div>Count 的平方:{
count * count}</div> </div> ) } export default App

提取元件

import { useState, useEffect, useRef} from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  const timerId = useRef()

  useEffect(() => {
    timerId.current = setInterval(() => {
      setCount(count =>
count + 1) }, 1000) return () => { clearInterval(timerId.current) } }, []) return <div>Count 的值:{count}</div> } function PowerCounter() { const [count, setCount] = useState(0) const timerId = useRef() useEffect(() => { timerId.current = setInterval(() => { setCount(count => count + 1) }, 1000) return () => { clearInterval(timerId.current) } }, []) return <div>Count 的平方:{count * count}</div> } function App() { return ( <div> <Counter /> <PowerCounter /> </div> ) } export default App

使用自定義 Hook 提取重複邏輯

import { useState, useEffect } from 'react'

// 自定義 Hook
function useCounter() {
  const [count, setCount] = useState(0)

  const timerId = useRef()

  useEffect(() => {
    timerId.current = setInterval(() => {
      setCount(count => count + 1)
    }, 1000)

    return () => {
      clearInterval(timerId.current)
    }
  }, [])

  return count
}

function Counter() {
  const count = useCounter()
  return <div>Count 的值:{count}</div>
}

function PowerCounter() {
  const count = useCounter()
  return <div>Count 的平方:{count * count}</div>
}

function App() {
  return (
    <div>
      <Counter />
      <PowerCounter />
    </div>
  )
}

export default App

示例2

在建立表單元素的時候通常都會將元件的狀態和表單元素進行繫結(value 屬性和 onChange事件),以實現資料同步。

每個表單都需要繫結 value 和 onChange,可以把這個公共的邏輯提取到自定義 Hook 中。

import { useState } from 'react'

function useUpdateInput(initialValue) {
  const [value, setValue] = useState(initialValue)
  return {
    value,
    onChange: event => setValue(event.target.value)
  }
}

function App() {
  const usernameInput = useUpdateInput('')
  const passwordInput = useUpdateInput('')

  const submitForm = event => {
    event.preventDefault()
    console.log(usernameInput.value)
    console.log(passwordInput.value)
  }

  return (
    <form onSubmit={submitForm}>
      <input type="text" name="username" {...usernameInput} />
      <input type="password" name="password" {...passwordInput} />
      <input type="submit" />
    </form>
  )
}

export default App

路由鉤子函式

當進入某個路由元件的時候,這個元件的 props 屬性會附加幾個物件:

在這裡插入圖片描述

React 路由模組(react-router-dom)提供了4個鉤子函式,用來獲取相關的路由資訊:

  • useHistory:獲取 history 物件
  • useLocation:獲取 location 物件
  • useRouteMatch:獲取 match 物件
  • useParams:獲取 match 物件下的 params 物件,即路由引數

示例

import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import { useHistory, useLocation, useRouteMatch, useParams } from 'react-router-dom'

function Index(props) {
  console.log('Index', props)
  console.log('history', useHistory())
  console.log('location', useLocation())
  return <div>首頁</div>
}

function News(props) {
  console.log('News', props)
  console.log('match', useRouteMatch())
  console.log('params', useParams())
  return <div>新聞</div>
}

function App() {
  return (
    <Router>
      <div>
        <Link to="/index">首頁</Link>
        <Link to="/news/100">新聞</Link>
      </div>
      <div>
        <Route path="/index" component={Index} />
        <Route path="/news/:id" component={News} />
      </div>
    </Router>
  )
}

export default App