文章目录
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState
是允许你在 React 函数组件中添加 state 的 Hook。稍后我们将学习其他 Hook。
如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其它转化为 class。现在你可以在现有的函数组件中使用 Hook。
二、为什么使用hooks
官方回答:
React 没有提供将可复用性行为“附加”到组件的途径(例如,把组件连接到 store)。如果你使用过 React 一段时间,你也许会熟悉一些解决此类问题的方案,比如 render props 和 高阶组件。但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解。如果你在 React DevTools 中观察过 React 应用,你会发现由 providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。尽管我们可以在 DevTools 过滤掉它们,但这说明了一个更深层次的问题:React 需要为共享状态逻辑提供更好的原生途径。
你可以使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。
复杂组件变得难以理解 为了解决这个问题,Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分。你还可以使用 reducer 来管理组件的内部状态,使其更加可预测。我们将在使用 Effect Hook 中对此展开更多讨论
难以理解的 class 为了解决这个问题,Hook 使你在非 class 的情况下可以使用更多的 React 特性。 从概念上讲,React 组件一直更像是函数。而 Hook 则拥抱了函数,同时也没有牺牲 React 的精神原则。Hook 提供了问题的解决方案,无需学习复杂的函数式或响应式编程技术。
三、使用方法
常用的hooks有以下几种
- useState,useEffect,useRef,useContext
- useSelector,useDispatch
- 自定义hooks
1. useState(state,setState)
函数组件不需要构造函数,可以通过调用 useState 来初始化 state
import React, { useState } from "react";
export default function Button() {
const [buttonText,setButtonText] = useState("点击前");
const handleClick = () => {
setButtonText("点击后");
}
return <button onClick={handleClick}>{buttonText}</button>;
}
2. useEffect
useEffect 拥有两个参数,第一个参数作为回调函数会在浏览器布局和绘制完成后调用,因此它不会阻碍浏览器的渲染进程。第二个参数是一个数组
import React, { useState, useEffect } from 'react';
const Count = (props) => {
const [count, setCount] = useState(0);
useEffect(() => {
let timer = setInterval(() => {
setCount(count + 1)
}, 1000);
// 当在 useEffect 的回调函数中返回一个函数时,这个函数会在组件卸载前被调用
return () => clearInterval(timer)
// count发生变化时再次执行
}, [count]);
return <div>
{count}
</div>
}
export default Count;
3.useRef
useRef
返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变
import React, { useRef, useEffect } from "react";
export default function Test() {
// 初始化一个useRef
const box = useRef(null);
useEffect(() => {
// 通过.current获取
console.log(box.current)
}, [])
return (
<div ref={box}>this is a box</div>
);
}
4.useContext
接收一个 context 对象,并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>
的 value
prop 决定
//父组件
import React from "react";
export const TextContext = React.createContext({});
<TextContext.Provider value={{
text: "this is a text"
}}>
<Child></Child>
</TextContext.Provider>
//子组件接收
import React, { useContext } from "react";
import { TextContext } from './parent';
export default function MemberPop() {
const { text } = useContext(TextContext);
}
5. 自定义hooks
自定义 Hook 是一个函数,其名称以 “use
” 开头,函数内部可以调用其他的 Hook。
/**
* 自定义一个hooks
* 返回鼠标所在位置
*/
import React, { useState, useEffect } from 'react'
const useMousePosition = () => {
const [position, setPosition] = useState({ x: 0, y: 0 })
useEffect(() => {
const updateMouse = (e) => {
setPosition({ x: e.clientX, y: e.clientY })
}
document.addEventListener('mousemove', updateMouse)
}, [])
return position
}
export default useMousePosition
//使用时引入自定义hooks
import React from 'react'
import useMousePosition from './hooks'
export default function App() {
const position = useMousePosition()
return (
<div>
<div>x: {position.x}</div>
<div>y: {position.y}</div>
</div>
)
}