hook
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。
【所以,hook的出现就是为了干掉class,因为class里面的state无法复用,导致了很多无用功】
useState
import React, { useState } from 'react';
function Example() {
  // 这是一个“函数组件”,或称为无状态组件
  const [count, setCount] = useState(0);
  // 声明一个叫 “count” 的 状态 变量,并将其设为0。
  // 初始值,可以是个变量传入,如props传入
  // 可以调用setCount来更新count
  // 想要多个变量,就多声明几个useState
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: '学习 Hook' }]);
  // 这些状态都能单独更新
  return (
    <div>
      <p>You clicked {count} times</p> // 这里直接能用count
      <button onClick={() => setCount(count + 1)}> // 直接用状态对应的更新函数
        Click me
      </button>
    </div>
  );
}useState,给函数添加了一个内部的state。返回[ 当前状态 ,更新状态的函数 ]
设定的初始值,可以不是对象。例子中的是数字。
更新函数类似this.setState
useState 不会自动合并更新对象。【?】
hook是特殊的函数,能引入react的特性。如添加state
react怎么知道,哪个state对应哪个useState?
靠的是 Hook 调用的顺序
useState useEffect
一组一个逻辑,以此来更新
useEffect
副作用(Side Effect)是指,函数或者表达式的行为,会交互到外部世界
修改外面的状态
除了返回语句外,还和外界有交互
Effect Hook 为你的函数式组件增添了执行 side effects 的能力。
它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途
【感觉就是,组件和外界的交互,全部都放在了这个useEffect()里面了】
不需要清理的side effects
import { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // 每次渲染后(第一次渲染+数据更新)
    // 可以理解为,这个函数里面内容,是渲染的一部分
    document.title = `You clicked ${count} times`; // 可以读取最新的count
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}在 React 类组件中,render 方法不应该引起 side effects 。 现在还为时过早——我们通常希望在 React 更新 DOM 之后, componentDidMount 和 componentDidUpdate 中,执行我们的 side effects 。
useEffect不会阻止浏览器更新屏幕,是一个异步的过程【?】 如果想要同步更新,可以用useLayoutEffect
需要清理的side effects
比如我们我们可能希望设置对某些外部数据源的订阅,这就需要清理,不然内存就装不下。 如果你的 effect 返回一个函数,React 将在清理时运行它:
import { useState, useEffect } from 'react';
function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // 清理的时候运行return函数
    // 如组件卸载、每次渲染之前
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}忘记正确处理 componentDidUpdate 是 React 应用程序中常见的 bug 漏洞。 比如props在组件出现在屏幕上时发生了变化,就会有个错误的在线记录,以及错误的卸载对象。 因此还要增加一个DidUpdate
可以将不相关的逻辑分成不同的 effects :
function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  // 第一个
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
  const [isOnline, setIsOnline] = useState(null);
  // 第二个
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
}【感觉这样,state和effect就能成为一小块,一小块应对一个逻辑】 能根据代码用途来分个代码
跳过清理来优化性能
类组件中,可以通过在componentDidUpdate 中编写与 prevProps 或 prevState 的额外比较来解决这个问题:【这是啥】
componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}hook的做法:
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes将数组作为可选的第二个参数传递给 useEffect ,如果在重新渲染之间没有更改这些值,react就会跳过引用effect 如果count值保持不变,就不会跑这条useEffect 数组中,只要有一个状态不同,就会更新effect
如果仅在装载和卸载时需要重新渲染,则可以将空数组([])作为第二个参数传递
hook规则
eslint插件:eslint-plugin-react-hooks 1. 只在最顶层使用hook 不要在循环,条件或嵌套函数中调用 Hook 确保 Hook 在每一次渲染中都按照同样的顺序被调用,保持hook状态的正确 2. 只在react中调用hook
自定义hook
如果我们想在两个组件当中共享逻辑,就能把它抽象到第三个函数中。 必须以use开头,不然react无法检查里面的hook
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 的顶层无条件地调用其他 Hook。
使用:
function FriendStatus(props) {
  // 直接当成函数调用
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}两个组件使用相同的hook函数,不会共享state
传递信息
Last updated
Was this helpful?