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

我们推荐启用 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 (
        <>
            
            
        
    );
}

六、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 ;
}
FancyInput = forwardRef(FancyInput);
渲染  的父组件可以调用 inputRef.current.focus()。

十、相关链接:
  • React的Hook让函数组件拥有class组件的特性!

你可能感兴趣的:(React的Hook让函数组件拥有class组件的特性!)