notes
  • notes
  • codes
    • 安卓脚本
    • redis入门指南
    • js 原型链
    • 如何发布npm
    • go字符串
    • redis
    • this指向
    • go1.13
    • go by example
    • hook
    • go指南 - 官网
    • git基本操作
  • vim
  • training
    • 9月19日 ubc讲座
    • zby
      • DAY 3 :硬拉 | ZBY
      • DAY 2:卧推 | ZBY
      • DAY 1:深蹲 | ZBY
      • DAY 4 :计划 | ZBY
    • 汉唐
    • 周旋康复课
  • book notes
    • 思考致富
    • 邓普顿教你逆向投资
    • 阮琦
    • 魔鬼经济学
    • 网络是怎样连接的
    • 好奇心
    • 魔鬼约会学5.0
    • 股票作手回忆录
    • 漫步华尔街
    • 码农翻身
    • 十分钟速成课 - 哲学
    • 魔鬼答疑
    • 大话数据结构
    • 魔鬼约会学笔记
    • 算法图解
  • 狼人杀
  • 图书馆
  • typora
  • imovie
Powered by GitBook
On this page
  • useState
  • react怎么知道,哪个state对应哪个useState?
  • useEffect
  • 不需要清理的side effects
  • 需要清理的side effects
  • 跳过清理来优化性能
  • hook规则
  • 自定义hook
  • 使用:
  • 传递信息

Was this helpful?

  1. codes

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

传递信息

Previousgo by exampleNextgo指南 - 官网

Last updated 5 years ago

Was this helpful?