React的Hook让函数组件拥有class组件的特性!

一、解决了什么问题?

Hook 是以 use 开头的特殊函数(useState、useEffect等),只能在 函数组件 内部使用。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。譬如 useState 就等同于 class组件中的state对象。

1、库的更新说明

Hook是React 16.8 新增特性, 在以下模块中包含了 React Hook 的稳定实现:

React DOM
React Native
React DOM Server
React Test Renderer
React Shallow Renderer

React Native 0.59 及以上版本支持 Hook。

请注意,要启用 Hook,所有 React 相关的 package 都必须升级到 16.8.0 或更高版本。如果你忘记更新诸如 React DOM 之类的 package,Hook 将无法运行。

二、Hook 规则与插件
1、规则
  • Hook只能用在React 的函数组件自定义Hook中。
  • Hook只能在函数最外层调用 ,在循环、条件判断或者子函数中调用都是不允许的。
2、插件

eslint-plugin-react-hooks 用于检查Hook代码是否符合规则的插件。

npm install eslint-plugin-react-hooks
3、插件链接:

我们推荐启用 eslint-plugin-react-hooks 中的 exhaustive-deps 规则。此规则会在添加错误依赖时发出警告并给出修复建议。


三、State Hook

State Hook 就是指 useState 这个特殊函数,让你不用编写class,就可以使用state特性,换言之就是让 函数组件 拥有 state 特性。详细用法,看这里!


四、Effect Hook

Effect Hook 就是指 useEffect 这个特殊函数,它让 函数组件 能在组件渲染完成后执行自定义操作。详细用法,看这里!


五、自定义Hook

自定义 Hook 是一个以 use 开头的自定义函数,其内部可以调用 Hook。

1、自定义Hook
import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
    const [isOnline, setIsOnline] = useState(null);

    useEffect(() => {
        function handleStatusChange(status) {
            setIsOnline(status.isOnline);
        }

        ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
        return () => {
            ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
        };
    });

    return isOnline;
}
2、使用自定义Hook
const friendList = [
    { id: 1, name: 'Phoebe' },
    { id: 2, name: 'Rachel' },
    { id: 3, name: 'Ross' },
];

function ChatRecipientPicker() {
    const [recipientID, setRecipientID] = useState(1);
    const isRecipientOnline = useFriendStatus(recipientID);

    return (
        <>
            <Circle color={isRecipientOnline ? 'green' : 'red'} />
            <select
                value={recipientID}
                onChange={e => setRecipientID(Number(e.target.value))}
            >
                {friendList.map(friend => (
                    <option key={friend.id} value={friend.id}>
                        {friend.name}
                    </option>
                ))}
            </select>
        </>
    );
}

六、Context Hook

Context Hook 就是指 useContext 这个特殊函数,解决了 props 在特殊场景下传递数据的烦恼。详细用法,看这里!


七、useReducer

useReducer 是 useState 的升级版本,对 setState 这个操作进行了拆分,可以根据不同类型,进行不同的逻辑计算,最后去改变 state 对象。详细用法,看这里!


八、useLayoutEffect

useLayoutEffect 的使用与 useEffect 一样,只是被调用的时间点不同。useEffect 是在浏览器绘制完成后被调用,useLayoutEffect 在浏览器绘制前被调用。


九、useDebugValue

在 React 开发者工具中显示自定义 hook 的标签。

function useFriendStatus(friendID) {
    const [isOnline, setIsOnline] = useState(null);

    // 在开发者工具中的这个 Hook 旁边显示标签
    // e.g. "FriendStatus: Online"
    useDebugValue(isOnline ? 'Online' : 'Offline');

    return isOnline;
}

// 第二个参数可以增加调试输出信息
useDebugValue(date, date => date.toDateString());

十、useCallback

设置一个回调函数,只有当依赖项的数值改变时,回调函数才被调用。如下,只有依赖项数组 [a,b] 有变动时,才会调用箭头函数。性能优化时,去除一些非必要的组件渲染。

const memoizedCallback = useCallback(
    () => {
        doSomething(a, b);
    },
    [a, b],
);

【备注】 useCallback(fn, deps) 相当于 useMemo(() => fn, deps)


十一、useMemo

把箭头函数 和 数组[a,b],作为参数传递给 useMemo ,当数组 [a,b] 的数值发生改变后,会在渲染期间调用箭头函数。如果没有第二个参数[a,b],那么每次渲染期间都会调用箭头函数。

先编写在没有 useMemo 的情况下也可以执行的代码 —— 之后再在你的代码中添加 useMemo,以达到优化性能的目的。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

【备注】 useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

React.memo 等效于 PureComponent,但它只比较 props。(你也可以通过第二个参数指定一个自定义的比较函数来比较新旧 props。如果函数返回 true,就会跳过更新。)

React.memo 不比较 state,因为没有单一的 state 对象可供比较。但你也可以让子节点变为纯组件。


十二、useImperativeHandle
// 把自己暴露给父组件,供父组件操作访问自己内部。
useImperativeHandle(ref, createHandle, [deps])

useImperativeHandle 应当与 forwardRef 一起使用:

// input 把自己暴露给父组件,父组件就可以调用其 focus 方法。
function FancyInput(props, ref) {
    const inputRef = useRef();
    useImperativeHandle(ref, () => ({
        focus: () => {
            inputRef.current.focus();
        }
    }));
    return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
渲染 <FancyInput ref={inputRef} /> 的父组件可以调用 inputRef.current.focus()。

十、相关链接:
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 课程目标 掌握函数组件的创建与使用; 掌握 React 常见 Hooks 使用; 掌握如何自定义 Hook。 课程...
    magic_pill阅读 2,784评论 0 0
  • 1、值捕获 造成数据不一致 异常 闭包内部变量为值捕获。如例子,点击按钮,设置age为1,调用request方法,...
    请叫我啊亮阅读 13,712评论 0 0
  • github的MD[https://github.com/liusanhong/study/blob/master...
    半个木头人阅读 1,950评论 0 0
  • 1 关于hook 1.1 为什么使用hook 在react类组件(class)写法中,有setState和生命周期...
    江湖yi山人阅读 5,858评论 0 3
  • 一、组件类 React的核心是组件, 在v16.8之前,组件的标准写法是类(class)。 以下为一个简单的组件类...
    郭_小青阅读 3,982评论 1 5