前言
在做 React 项目时我们可以选择使用 class 类组件 或者 function 函数组件,在 React 16.8 之前,使用函数组件是为一个无状态的组件通常只做为展示,渲染组件工作。在 React 16.8 里,react 新增了一个特性—— Hook,能让我们在不使用 class 的情况下,也可以使用 state 以及 React 的其它特性。
介绍
Hooks 其实就是一个 Javascript 的函数。在 React 里,它就给我们提供了几个 hook 供我们使用,像 useState、userContext、useEffect等等,在 React 里经常使用的一些库如 react-router-dom,就有着 useNavigate、 useRoutes等,去起到切换路由、使用路由表等工作,能够帮我们处理一些事务,所以去做 react 项目时,它允许在函数式组件中使用状态和其他 React 特性。Hooks 旨在解决在类组件中使用复杂逻辑、共享状态和处理副作用时的一些问题,使得函数式组件具有更多的能力和灵活性。
使用
让我们先了解下 React 给我们提供比较常用的 hook,能够帮我们做到哪些事情
useState
useState 用于在函数组件里调用它来满足给组件添加一些内部state(状态)。
从 react 中导入 useState 使用,使用 useState 可以传入初始值,执行返回一个有状态值和一个函数来更新它。
在后续重新渲染期间,useState 返回的第一个值将始终是应用更新后的最新状态,拿到最新值才进行最终的渲染,提高性能。
import React, { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(1);
return (
<div>
{/* 点击按钮 +1 */}
<h1>当前 count 值:{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
useEffect
useEffect (副作用钩子) 用于在 React 组件需要在渲染后执行某些操作,因为 useEffect 保证是在执行 DOM 更新完成之后才调用它,在第一次渲染之后和每次更新之后都会去执行,可以在里面获取到最新的 DOM。
import React, { useState, useEffect } from 'react';
export default function Counter() {
const [count, setCount] = useState(1);
// 相当于 componentDidMount 和 componentDidUpdate 组件生命钩子函数
useEffect(() => {
console.log(`当前最新 count 值 为 ${count} `)
});
// 也可以给予第二个参数,用于监听某个 state 值
useEffect(() => {
console.log(`当前最新 count 值 为 ${count} `)
}, [count]); // 仅在 count 更改时更新
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
useContext
userContext 它接受一个上下文对象,并返回该上下文的当前值,可以帮助我们跨越组件层级直接传递变量,不需要手动传值给每个子组件,就可以做到实现数据共享。
import { useState, createContext, useContext } from 'react';
const CountContext = createContext(1)
function Home() {
// 定义要传递的值
const [ count, setCount] = useState(1)
return (
<div>
<CountContext.Provider value={ count }>
<Header />
</CountContext.Provider>
<p>Hello, home! 当前值为 { count }</p>
<button onClick={() => setCount(count + 1)}>{'点击+1'}</button>
</div>
);
}
const Header = ()=> {
// 接收上面定义的上下文对象
const count = useContext(CountContext)
return (
<div>
// 该 count 值随 Home 组件的点击事件变化
<p>Hello, Header! 当前 count 值为 { count }</p>
</div>
);
}
export default Home
除去以上三种 Hooks ,React还提供了其他Hooks函数,如 useReducer、useCallback、useMemo、useRef 等,以满足不同的需求和场景。
那么我们想要创建自己的 hook 要怎么做呢?
自定义 hook
在自定义 Hooks 中通常以 use 开头,像 useState、useContext等都是这样的。
这里设置一个 count 值加 1 和重置为初始值,定义好后就可以在组件中导入使用 useCount 函数。
import { useState } from "react";
function useCount(initialState) {
const [count, setCount] = useState(initialState);
const handleAdd = () => {
setCount(count + 1);
};
const resetCount = () => {
setCount(initialState);
};
return [count, handleAdd, resetCount];
}
export default useCount;
// 导入使用自定义 Hooks
import useCount from './useCount';
function Home() {
const [ count, handleAdd, resetCount] = useCount(0)
return (
<div>
<p>Hello, home! 当前值为 { count }</p>
<button onClick={handleAdd}>点击+1</button>
<button onClick={resetCount}>重置</button>
</div>
);
}
export default Home
总结
- 有着更好的逻辑和状态的复用,通过自定义 Hooks ,将一些重复使用的逻辑和状态封装称为一个函数,可以在不同的组件中使用该函数,去共享,避免组件之间状态和逻辑重复编写的问题
- 可以灵活的去设计组件,在函数式组件中使用状态、副作用和 React 的其它特性,使代码更加清晰
- 使用 Hooks,能极大简化代码,使逻辑清晰明了,提高代码的可读性和可维护性