一、描述:

React Hook 一览 这边文章里面简单介绍了一下 React Hook 以及基本的使用情况。

里面拿出了一个简单的计数的例子,使用了 useState Hook:

import { useState } from 'react';
function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

二、等效的类组件

现在使用类组件实现一个和上面使用 Hook 一样效果的组件:

class Example 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

React 文档提了一下,为什么使用计数器而没有使用更加现实的例子。因为只是最基础的使用 Hooks,专注的是 API,而不是应用。

三、Hook 和 Function 组件

基础的 Function 组件基本都是下面两种形态:

const Example = (props) => {
  // You can use Hooks here!
  return <div />;
}

或者:

function Example(props) {
  // You can use Hooks here!
  return <div />;
}

有的人喜欢称这种组件为 无状态组件,但是一般都叫函数声明组件。而现在 React 能够在函数声明组件中使用 state,所以已经不能称为无状态组件。 React 则喜欢称为 Function Components

四、什么是 Hook

示例使用中,首先是从 React 中引入 useState:

import { useState } from 'react';

function Example() {
  // ...
}

1、什么是 Hook?

Hook 是一种特殊的 function,可以让你能够 hook into React 的功能。比如, useState 是一个 Hook,允许你将 React state 添加到 function 组件。

2、什么时候使用 Hook?

如果写了一个 function 组件,并且意识到需要为这个组件添加一些 state,那么之前的做法是需要将这个组件转成一个 class 组件。而有了 Hook 之后,就可以直接通过 Hook 在 function 组件中做到这一点。

需要注意的是,什么时候或者在哪里能够使用 Hook 是有一个约定的,具体的见文档:https://reactjs.org/docs/hooks-rules.html

五、声明一个 state 变量

在 class 组件中,一般在构造函数中通过 this.state = {count: 0} 来初始化计数为 0:

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

在 function 组件中,不能分配或者是读取 this.state,而做法是直接在组件内部调用 useState Hook:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

1、调用 useState 有什么作用

上面声明了一个 “state 变量”,而变量的名字是 countcount 只是一个名称,可以是任何值。这是一种在函数调用之间 “保留” 某些值的方法 —— useState 是一种和在 Class 组件使用 this.state 相同功能的新方法。通常,函数退出的时候,变量会 “消失”,但是 React 会保留声明的状态变量。

2、传递给 useState 的参数是什么?

useState 的唯一参数是 Hook 的 state 的初始值,state 不一定是对象,可以是任何值。如果需要的话,可以保留一个数字或者字符串。而在计数器的示例中,只需要一个数字来表示用户点击的is胡,因此 0 作为变量的初始状态。(如果想在状态中存储两个不同的值,需要使用两次 useState

3、useState 返回什么

useState 返回一对值:当前状态和更新这个状态的方法。这就是为什么写 const [count, setCount] = useState()。这和类中的 this.state.countthis.setState({count:count}) 类似,只不过是成对出现的。

上面的代码中声明了一个名为 count 的 state 变量,并将其设置为 0。React 将机主它在 re-render 之间的当前值,并为函数提供最新的值。如果需要更新当前的技术,直接调用 setCount 就行。

 4、为什么 useState 没有起名叫 createState

Create 是不准确的,因为 state 仅在组件第一次呈现的时候创建,而在下一次渲染期间,useState 为我们提供了当前的 state。否则就不是 "state" 了,Hook 的名字总是使用 use 也是有原因的,而在 Rules of Hooks 文档中可以看到,

六、读取 state

在类组件中,如果需要获取 count,会通过 this.state.count 读取:

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

而在 function 组件中,可以直接使用 count 变量:

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

七、更新 state

在类组件中,需要通过 this.setState 来更新 count:

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

在 function 组件中,已经把 setCountcount 声明为变量,可以直接使用,不需要使用 this

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

八、总结

1:  import { useState } from 'react';
 2: 
 3:  function Example() {
 4:    const [count, setCount] = useState(0);
 5:
 6:    return (
 7:      <div>
 8:        <p>You clicked {count} times</p>
 9:        <button onClick={() => setCount(count + 1)}>
10:         Click me
11:        </button>
12:      </div>
13:    );
14:  }

第1行:

我们从 React 导入 useState Hook,允许将本地 state 保存在 function 组件中。

第4行:

在上面的组件中,通过调用 useState Hook 声明了一个新的 state 变量,它返回一对有开发者定义的名称的值:比如 count,通过传递 0 作为为一个 useState 参数将其初始化为 0. 第二个返回的值本身是一个函数,能够允许开发者更新计数,而命名也有开发者定义,比如 setCount

第9行:

当用户点击的时候,使用新值来调用 setState。然后,React 将 re-render 组件,并把新的 count 值传递给它。

九、提示:[]意味着什么

在使用 useState 的时候已经看到了方括号,也就是 []

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

左侧的名称不是 React API 的一部分,可以命名自己的状态变量:

const [fruit, setFruit] = useState('banana');

关于 ES6 的解构赋值就不过多解释了。

十、使用多个 state 变量

将状态变量声明为一对 [something, setSomethin] 的形式也非常方便,而如果要使用多个状态变量,可以声明多次,能够保证不同的变量名称和方法都不一样:

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

上面的组件形式,能够将 agefruit 和 todos 作为局部变量,可以单独更新它们。

function handleOrangeClick() {
    // Similar to this.setState({ fruit: 'orange' })
    setFruit('orange');
  }

有些时候,不一定需要使用很多的 state 和 setSomething,因为 state 变量能够很好的保存对象和数组,因此仍旧可以将数据组合在一起。但是,和类组件中的 this.setState 不同,更新 state 变量总是替换,而不是合并。