React -- State Hook 详细介绍(函数组件也可以使用state了)

目录

Hook 简介

Hook 对 React 意味着什么?

Hook 的使用动机是什么?

1、在组件之间复用状态逻辑很难

2、复杂组件变得难以理解

3、难以理解的 class

State Hook

基本例子

Hook 和 函数组件

Hook 是什么?

声明 State

useState 调用

useState 参数

useState 返回值

读取 State

更新 State

示例分析

步骤分析

方括号的作用

使用多个 state 变量

总结


Hook 简介

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

Hook 对 React 意味着什么?

  • 完全可选的。 你无需重写任何已有代码就可以在一些组件中尝试 Hook。但是如果你不想,你不必现在就去学习或使用 Hook
  • 100% 向后兼容的。 Hook 不包含任何破坏性改动
  • 现在可用。 Hook 已发布于 v16.8.0

没有计划从 React 中移除 class 。Hook 不会影响你对 React 概念的理解。 恰恰相反,Hook 为已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。

Hook 的使用动机是什么?

在使用 React 中,或许会遇见过以下的窘境

1、在组件之间复用状态逻辑很难

React 没有提供将可复用性行为“附加”到组件的途径(例如,把组件连接到 store)。render props 和 高阶组件 或许可以解决此类问题,但是这类方案需要重新组织组件结构,这可能会很麻烦,使代码难以理解。由 providers,consumers,高阶组件,render props 等其他抽象层组成的组件会形成“嵌套地狱”。

可以使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。

2、复杂组件变得难以理解

组件起初很简单,但是逐渐会被状态逻辑和副作用充斥。每个生命周期常常包含一些不相关的逻辑。例如,组件常常在 componentDidMount 和 componentDidUpdate 中获取数据。但是,同一个 componentDidMount 中可能也包含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中清除。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。如此很容易产生 bug,并且导致逻辑不一致。

在多数情况下,不可能将组件拆分为更小的粒度,因为状态逻辑无处不在。这也给测试带来了一定挑战。同时,这也是很多人将 React 与状态管理库结合使用的原因之一。但是,这往往会引入了很多抽象概念,需要你在不同的文件之间来回切换,使得复用变得更加困难。

为了解决这个问题,Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分,可以使用 reducer 来管理组件的内部状态,使其更加可预测。

3、难以理解的 class

除了代码复用和代码管理会遇到困难外,学习class 是 React 的一大屏障,理解 JavaScript 中 this 的工作方式,与其他语言存在巨大差异。还不能忘记绑定事件处理器。没有稳定的语法提案,这些代码非常冗余,或许你理解 props,state 和自顶向下的数据流,但对 class 却一筹莫展。

使用 class 组件会无意中鼓励开发者使用一些让优化措施无效的方案。class 也给目前的工具带来了一些问题。例如,class 不能很好的压缩,并且会使热重载出现不稳定的情况。

为了解决这些问题,Hook 使你在非 class 的情况下可以使用更多的 React 特性。 从概念上讲,React 组件一直更像是函数。而 Hook 则拥抱了函数,同时也没有牺牲 React 的精神原则。Hook 提供了问题的解决方案,无需学习复杂的函数式或响应式编程技术。

以上就是 React Hook 的一些简要介绍,接下来详细介绍 Hook 的其中之一:State Hook。

State Hook

基本例子

如下例子,在 React 中,使用 class 的方式创建一个计时器

class Count extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

state 初始值为 { count: 0 } ,当用户点击按钮后,我们通过调用 this.setState() 来增加 state.count

之前,我们在创建具有状态的组件时,使用的是 class 的方式;而 Hook 可以另函数组件拥有更多的 React 特性,如 state 。使用 Hook 改写上面的 class 组件创建方式

import React, { useState } from 'react';

function Count() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Hook 和 函数组件

React 的函数组件

const Count = (props) => {
  // 你可以在这使用 Hook
  return <div />;
}

 或是这样

function Count(props) {
  // 你可以在这使用 Hook
  return <div />;
}

之前可能把它们叫做“无状态组件”,但现在为它们引入了使用 React state 的能力,所以更喜欢称之为”函数组件”。

看到这里,此处 Hook 到底是什么?

Hook 是什么?

在上面的示例中,引入 React 中 useState 的 Hook

import React, { useState } from 'react';

function Count() {
  // ...
}

Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你在 React 函数组件中添加 state 的 Hook。 如果在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其它转化为 class,现在可以在现有的函数组件中使用 Hook。

声明 State

使用 class 方式,在构造函数中设置 this.state 为 { count: 0 } 来初始化 count state 为 0

class Count extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
}

在函数组件中,没有 this,所以不能分配或读取 this.state。我们直接在组件中调用 useState Hook

import React, { useState } from 'react';

function Count() {
  // 声明一个叫 “count” 的 state 变量
  const [count, setCount] = useState(0);
}

useState 调用

它定义一个 “state 变量”。我们的变量叫 count, 但是我们可以叫他任何名字,比如 banana。这是一种在函数调用时保存变量的方式 —— useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会“消失”,而 state 中的变量会被 React 保留。

useState 参数

useState() 方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字或字符串对其进行赋值,而不一定是对象。在示例中,只需使用数字来记录用户点击次数,所以我们传了 0 作为变量的初始 state。(如果我们想要在 state 中存储两个不同的变量,只需调用 useState() 两次即可。)

useState 返回值

返回值为当前 state 以及更新 state 的函数。这就是我们写 const [count, setCount] = useState() 的原因。这与 class 里面 this.state.count 和 this.setState 类似,唯一区别就是你需要成对的获取它们。

重看以下例子

import React, { useState } from 'react';

function Count() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);
}

声明了一个叫 count 的 state 变量,然后把它设为 0。React 会在重复渲染时记住它当前的值,并且提供最新的值给我们的函数。我们可以通过调用 setCount 来更新当前的 count

读取 State

在 class 中显示当前的 count,我们读取 this.state.count

<p>You clicked {this.state.count} times</p>

在函数中,我们可以直接用 count

<p>You clicked {count} times</p>

更新 State

在 class 中,我们需要调用 this.setState() 来更新 count 值

<button onClick={() => this.setState({ count: this.state.count + 1 })}>
  Click me
</button>

在函数中,我们使用 setCount 更新 count

<button onClick={() => setCount(count + 1)}>
  Click me
</button>

示例分析

步骤分析

// 引入 React 中的 useState Hook。它让我们在函数组件中存储内部 state。
import React, { useState } from 'react';

function Count() {
  // 在 Count 组件内部,我们通过调用 useState Hook 声明了一个新的 state 变量。
  // 它返回一对值给到我们命名的变量上。我们把变量命名为 count,因为它存储的是点击次数。
  // 我们通过传 0 作为 useState 唯一的参数来将其初始化为 0。第二个返回的值本身就是一个函数。
  // 它让我们可以更新 count 的值,所以我们叫它 setCount。
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <!-- 当用户点击按钮后,我们传递一个新的值给 setCount。React 会重新渲染 Count 组件,并把最新的 count 传给它。 -->
      <button onClick={() => setCount(count + 1)}>
       Click me
      </button>
    </div>
  );
}

方括号的作用

const [count, setCount] = useState(0);

以上是 JavaScript 语法叫数组解构。它意味着我们同时创建了 count 和 setCount 两个变量,count 的值为 useState 返回的第一个值,setCount 是返回的第二个值。它等价于下面的代码

const countStateVariable = useState(0);   // 返回一个有两个元素的数组
const count = countStateVariable[0];   // 数组里的第一个值
const setCount = countStateVariable[1];   // 数组里的第二个值

当我们使用 useState 定义 state 变量时候,它返回一个有两个值的数组。第一个值是当前的 state,第二个值是更新 state 的函数。使用 [0] 和 [1] 来访问有点令人困惑,因为它们有特定的含义。这就是我们使用数组解构的原因。

使用多个 state 变量

将 state 变量声明为一对 [something, setSomething] 也很方便,因为如果我们想使用多个 state 变量,它允许我们给不同的 state 变量取不同的名称

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

在以上组件中,我们有局部变量 agefruit 和 todos,并且我们可以单独更新它们

function handleAgeClick() {
  // 和 this.setState({ age: 19 }) 类似
  setAge(19);
}

总结

以上内容中,我们了解了 React 提供的 useState Hook,有时候我们也叫它 “State Hook”。它让我们在 React 函数组件上添加内部 state 。

我们还学到了什么是 Hook。Hook 是能让你在函数组件中“钩入” React 特性的函数。它们名字通常都以 use 开始,不妨试试在项目中使用。

(更多前端相关博客请查看我的主页喔~~~关注我,一起学前端,共同进步)

猜你喜欢

转载自blog.csdn.net/qq_41809113/article/details/122500836