Bootstrap

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

;