自定义 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