一起来了解React的Hook

目录
  • StateHook
    • 声明多个state变量
    • 那么,什么是Hook?
  • EffectHook
  • Hook使用规则
  • 自定义Hook
  • 其他Hook
  • 总结

State Hook

这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加:

import React, { useState } from 'react';
function Example() {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

在这里,useState 就是一个 Hook (等下我们会讲到这是什么意思)。通过在函数组件里调用它来给组件添加一些内部 state。React 会在重复渲染时保留这个 stateuseState 会返回一对值:当前状态一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。(我们会在使用 State Hook 里展示一个对比 useState 和 this.state 的例子)。

useState 唯一的参数就是初始 state。在上面的例子中,我们的计数器是从零开始的,所以初始 state 就是 0。值得注意的是,不同于 this.state,这里的 state 不一定要是一个对象 —— 如果你有需要,它也可以是。这个初始 state 参数只有在第一次渲染时会被用到。

声明多个 state 变量

你可以在一个组件中多次使用 State Hook:

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

数组解构的语法让我们在调用 useState 时可以给 state 变量取不同的名字。当然,这些名字并不是 useState API 的一部分。React 假设当你多次调用 useState 的时候,你能保证每次渲染时它们的调用顺序是不变的。后面我们会再次解释它是如何工作的以及在什么场景下使用。

那么,什么是 Hook?

Hook 是一些可以让你在函数组件里 " 钩入" React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。(我们不推荐把你已有的组件全部重写,但是你可以在新组件里开始使用 Hook。)

React 内置了一些像 useState 这样的 Hook。你也可以创建你自己的 Hook 来复用不同组件之间的状态逻辑。我们会先介绍这些内置的 Hook。

Effect Hook

你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

例如,下面这个组件在 React 更新 DOM 后会设置一个页面标题:

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— 包括第一次渲染的时候。

副作用函数还可以通过返回一个函数来指定如何“清除”副作用。例如,在下面的组件中使用副作用函数来订阅好友的在线状态,并通过取消订阅来进行清除操作:

import React, { 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 () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

在这个示例中,React 会在组件销毁时取消对 ChatAPI 的订阅,然后在后续渲染时重新执行副作用函数。(如果传给 ChatAPI 的 props.friend.id 没有变化,你也可以告诉 React 跳过重新订阅。)

跟 useState 一样,你可以在组件中多次使用 useEffect :

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);
  }
  // ...

通过使用 Hook,你可以把组件内相关的副作用组织在一起(例如创建订阅及取消订阅),而不要把它们拆分到不同的生命周期函数里。

Hook 使用规则

Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中,我们稍后会学习到。)

自定义 Hook

有时候我们会想要在组件之间重用一些状态逻辑。目前为止,有两种主流方案来解决这个问题:高阶组件和 render props。自定义 Hook 可以让你在不增加组件的情况下达到同样的目的。

前面,我们介绍了一个叫 FriendStatus 的组件,它通过调用 useState 和 useEffect 的 Hook 来订阅一个好友的在线状态。假设我们想在另一个组件里重用这个订阅逻辑。

首先,我们把这个逻辑抽取到一个叫做 useFriendStatus 的自定义 Hook 里:

import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });
  return isOnline;
}

它将 friendID 作为参数,并返回该好友是否在线:

现在我们可以在两个组件中使用它:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

每个组件间的 state 是完全独立的。Hook 是一种复用状态逻辑的方式,它不复用 state 本身。事实上 Hook 的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。

自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 use 开头并调用其他 Hook,我们就说这是一个自定义 Hook。 useSomething 的命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。

你可以创建涵盖各种场景的自定义 Hook,如表单处理、动画、订阅声明、计时器,甚至可能还有更多我们没想到的场景。我们很期待看到 React 社区会出现什么样的自定义 Hook。

其他 Hook

除此之外,还有一些使用频率较低的但是很有用的 Hook。比如,useContext 让你不使用组件嵌套就可以订阅 React 的 Context。

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

另外 useReducer 可以让你通过 reducer 来管理组件本地的复杂 state

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • React之Hooks详解

    目录 什么是钩子(hooks) 类组件 函数组件 为什么创造Hooks 总结 什么是钩子(hooks) 消息处理的一种方法, 用来监视指定程序 函数组件中需要处理副作用,可以用钩子把外部代码"钩"进来 常用钩子:useState, useEffect, useContext, useReducer Hooks一律使用use前缀命名:useXXX 类组件 函数组件 一类特殊的函数,为你的函数式组件注入特殊的功能 为什么创造Hooks 有些类组件冗长且复杂,难以复用 结局方案:无状态组件与

  • React从Class方式转Hooks详解

    目录 React Hooks 前言 Why Hooks ? For Class For Function Class & Hooks 对比 Hooks如何保存组件状态和使用生命周期? 1.useState:让函数具有维持状态的能力 2.useEffect:执行副作用 总结 React Hooks 前言 之前工作三年中一直在用class方式去写前端功能页面这些,其实接触hooks也是有一定时间了.在第一次接触的时候应该是看了一门关于electron+react的项目的课程的时候.当时主要是去看el

  • React Hook之使用State Hook的方法

    目录 等价的class示例 Hook和函数组件 Hook是什么? 声明State变量 读取State 更新State 小结 提示:方括号有什么用? 提示:使用多个state变量 总结 Hook 简介章节中使用下面的例子介绍了 Hook: import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to compo

  • React中10种Hook的使用介绍

    目录 React Hook是什么? React目前提供的Hook 1.useState 2.useEffect & useLayoutEffect 3.useMemo & useCallback 4.useRef 5.useContext 6.useReducer React Hook是什么? React官网是这么介绍的: Hook 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 完全可选的 你无需重写任何已有

  • React Hook之使用Effect Hook的方法

    目录 无需清除的effect 使用class的示例 使用Hook的示例 详细说明 需要清除的effect 使用Class的示例 使用Hook的示例 小结 使用Effect的提示 提示:使用多个Effect实现关注点分离 解释:为什么每次更新的时候都要运行Effect 提示:通过跳过Effect进行性能优化 总结 Effect Hook 可以让你在函数组件中执行副作用操作 import React, { useState, useEffect } from 'react'; function Ex

  • react中hook介绍以及使用教程

    前言 最近由于公司的项目开发,就学习了在react关于hook的使用,对其有个基本的认识以及如何在项目中去应用hook.在这篇博客中主要从以下的几个点进行介绍: hook简介 hook中常用api的使用 hook在使用过程中需要去注意的地方 hook中怎样去实现class组件中的声明周期函数 hook 首先介绍关于hook的含义,以及其所要去面对的一些场景 含义:Hook 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

  • React自定义hook的方法

    目录 什么是hook 常用的有哪些hook 自定义hook 什么是hook Hook是 React 16.8 的新增特性.它通常与函数式组件同时使用.可以使函数式组件在不编写 class 的情况下,可以拥有class组件的状态.生命周期.引用等功能. 常用的有哪些hook React中常用的hooks有: useState 状态管理 useEffect 生命周期 useContext 跨组件数据传递 useRef 组件引用 .... 自定义hook 自定义hook其实就是自定义函数,与我们写函数

  • React中hook函数与useState及useEffect的使用

    目录 1. 简介 2. useState使用 3. useEffect使用 useEffect发起网络请求 1. 简介 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数组件,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖于类组件来获取数据,处理数据,并向下传递参数给 UI 组件进行渲染.React在v16.8 的版本中推出了 React Hooks 新特性,Hook是一套工具函数的集合,它增强了函数

  • 一起来了解React的Hook

    目录 StateHook 声明多个state变量 那么,什么是Hook? EffectHook Hook使用规则 自定义Hook 其他Hook 总结 State Hook 这个例子用来显示一个计数器.当你点击按钮,计数器的值就会增加: import React, { useState } from 'react'; function Example() { // 声明一个叫 "count" 的 state 变量. const [count, setCount] = useState(0

  • React hook实现简单的websocket封装方式

    目录 React hook实现websocket封装 react自定义hook解决websocket连接,useWebSocket 1.描述 2.代码 React hook实现websocket封装 新建websocket.ts文件 import {useState, useRef, useEffect} from 'react' const useWebsocket = ({ url:string, verify }) => {     const ws = useRef<WebSocket

  • React Hook - 自定义Hook的基本使用和案例讲解

    目录 自定义Hook 自定义Hook基本使用 自定义Hook案例练习 获取Context数据 获取窗口滚轮数据 自定义Hook 自定义Hook基本使用 自定义Hook本质上只是一种函数代码逻辑的抽取,严格意义上来说,它本身并不算React的特性. 例如有这样一个需求: 所有的组件在创建和销毁时都进行打印 组件被创建: 打印组件被创建了; 组件被销毁: 打印组件被销毁了; 如果每个组件我们都单独编写是非常繁琐的, 并且有许多重复代码; 我们可以将实现这样逻辑相同的代码抽离为一个自定义的Hook i

  • 详解React Hooks是如何工作的

    1. React Hooks VS 纯函数 React Hook 说白了就是 React V18.6 新增的一些 API,API的本质就是提供某种功能的函数接口.因此,React Hooks 就是一些函数,但是 React Hooks 不是纯函数. 什么是纯函数呢?就是此函数在相同的输入值时,需产生相同的输出,并且此函数不能影响到外面的数据. 简单理解就是函数里面不能用到在外面定义的变量,因为如果用到了外面定义的变量,当外面的变量改变时会影响函数内部的计算,函数也会影响到外面的变量. 对于 Re

  • vue3中的hook简单封装

    目录 vue3的hook封装 vue3的hooks总结 下面总结一下如何去书写hooks 计数器的hook vue3的hook封装 vue3最新鲜的就是组合式API了,通过组合式API我们可以把一些复杂的逻辑或一些常用的逻辑封装成一个个hook来进行调用,这样的方式也更易于维护. 使用 import useTest from "../../hooks/useTest"; export default defineComponent({   name: "vue3Test&qu

  • react中使用usestate踩坑及解决

    目录 usestate的常规用法 useState遇到的坑 1.useState不适合复杂对象的更改 2.useState异步回调的问题 3.根据hook的规则,使用useState的位置有限制 4.使用useState,回调函数形式更改数据 5.useState存入的值只是该值的引用(引用类型) 6.useState,如果保存引用数据,useEffect检测不到变化? 7.useState无法保存一个函数 useState实现原理 usestate的常规用法 在react框架中,不适用类组件,

  • 浅谈React useDebounce 防抖原理

    目录 1.js防抖 2.React custom Hook useDebounce 1.js防抖 // func 需要去抖动的函数 delay 延时执行时间 const debounce = (func, delay) => { let timeout; //...param es6语法 获取形参数组 argaments return (...param) => { // 每次 进入清除上一个已经执行/未执行的定时器 if (timeout) { clearTimeout(timeout);

随机推荐