• React Hook


    基本概念

    Hook 是能让你在函数组件中“钩入” React 特性的函数,它们名字通常都以 use 开始。

    Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。

    State Hook

    function ExampleWithManyStates() {
      // 声明多个 state 变量
      const [age, setAge] = useState(42);
      const [fruit, setFruit] = useState('banana');
      const [todos, setTodos] = useState([{ text: '学习 Hook' }]);
    

    State 变量可以很好地存储对象和数组,因此,你仍然可以将相关数据分为一组。然而,不像 class 中的 this.setState,更新 state 变量总是替换它而不是合并它。

    函数式更新

    如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState。该函数将接收先前的 state,并返回一个更新后的值。

    function Counter({initialCount}) {
      const [count, setCount] = useState(initialCount);
      return (
        <>
          Count: {count}
          <button onClick={() => setCount(initialCount)}>Reset</button>
          <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
          <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
        </>
      );
    }
    

    与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。

    setState(prevState => {
      // 也可以使用 Object.assign
      return {...prevState, ...updatedValues};
    });
    

    Effect Hook

    通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。

    你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。

    如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。

    componentDidMountcomponentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同。

    如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它。 React 在执行当前 effect 之前对上一个 effect 进行清除。

      useEffect(() => {
        function handleStatusChange(status) {
          setIsOnline(status.isOnline);
        }
    
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });
    

    Hook 允许我们按照代码的用途分离他们, 而不是像生命周期函数那样。

    在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevPropsprevState 的比较逻辑解决:

    componentDidUpdate(prevProps, prevState) {
      if (prevState.count !== this.state.count) {
        document.title = `You clicked ${this.state.count} times`;
      }
    }
    

    性能优化

    你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:

    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [count]); // 仅在 count 更改时更新
    

    如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。

    要记住 effect 外部的函数使用了哪些 props 和 state 很难。这也是为什么 通常你会想要在 effect 内部 去声明它所需要的函数。

    Hook 规则

    • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
    • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。

    那么 React 怎么知道哪个 state 对应哪个 useState?答案是 React 靠的是 Hook 调用的顺序。因为我们的示例中,Hook 的调用顺序在每次渲染中都是相同的,所以它能够正常工作:

    // ------------
    // 首次渲染
    // ------------
    useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
    useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
    useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
    useEffect(updateTitle)     // 4. 添加 effect 以更新标题
    
    // -------------
    // 二次渲染
    // -------------
    useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
    useEffect(persistForm)     // 2. 替换保存 form 的 effect
    useState('Poppins')        // 3. 读取变量名为 surname 的 state(参数被忽略)
    useEffect(updateTitle)     // 4. 替换更新标题的 effect
    
    // ...
    

    如果我们想要有条件地执行一个 effect,可以将判断放到 Hook 的内部

    自定义 Hook

    自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook。以use开头的原因是react需要检查你的 Hook 是否违反了 Hook 的规则

    自定义 Hook 不需要具有特殊的标识。我们可以自由的决定它的参数是什么,以及它应该返回什么(如果需要的话)。

    自定义 Hook 是一种自然遵循 Hook 设计的约定,而并不是 React 的特性。

    import React, { 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;
    }
    

    本质上是用一个公共函数将多个Hook方法进行了封装

  • 相关阅读:
    vue自定义指令clickoutside使用以及扩展用法
    抓包工具Charles的使用教程
    vue之element-ui文件上传
    Vue省市区三级联选择器V-Distpicker的使用
    Vue如何封装多个全局过滤器到一个文件
    vue工程中使用iconfont在线CDN不生效的问题
    es6 Null 传导运算符
    js中布尔值为false的六种情况
    vue-vli3创建的项目配置热更新
    js思维导图
  • 原文地址:https://www.cnblogs.com/goOtter/p/10959488.html
Copyright © 2020-2023  润新知