React Hooks 工作原理

我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件却不能?

React 早期版本,类组件可以通过继承PureComponent来优化一些不必要的渲染,相对于函数组件,React 官网没有提供对应的方法来缓存函数组件以减少一些不必要的渲染,直接 16.6 出来的 React.memo函数。
React 16.8 新出来的Hook可以让React 函数组件具有状态,并提供类似 componentDidMountcomponentDidUpdate等生命周期方法。
Hooks不会替换类,它们只是一个你可以使用的新工具。

Hooks的例子:

OneTimeButton 是函数组件,所做的事情就是当我们点击的时候调用 sayHi 方法函数组件

import React from 'react';
import {
    
     render } from 'react-dom';

function OneTimeButton(props) {
    
    
  return (
    <button onClick={
    
    props.onClick}>
        点我
    </button>
  )
}

function sayHi() {
    
    
  console.log('yo')
}

render(
  <OneTimeButton onClick={
    
    sayHi}/>,
  document.querySelector('#root')
)

让这个组件做的是,跟踪它是否被点击,如果被点击了,禁用按钮,就像一次性开关一样。

但它需要一个state,因为是一个函数,它不可能有状态(React 16.8之前),所以需要重构成类。

class OneTimeButton extends React.Component {
    
    
  state = {
    
    
    clicked: false
  }

  handleClick = () => {
    
    
    this.props.onClick();

    // Ok, no more clicking.
    this.setState({
    
     clicked: true });
  }

  render() {
    
    
    return (
      <button
        onClick={
    
    this.handleClick}
        disabled={
    
    this.state.clicked}
      >
        You Can Only Click Me Once
      </button>
    );
  }
}

使用 Hook 添加 State

用新的 useState hook向普通函数组件添加状态:

import React, {
    
     useState } from 'react'

function OneTimeButton(props) {
    
    
  const [clicked, setClicked] = useState(false)
  
  function doClick() {
    
    
    props.onClick();
    setClicked(true)
  }

  return (
    <button
      onClick={
    
    clicked ? undefined : doClick}
      disabled={
    
    clicked}
    >
      点我
    </button>
  )
}

useState是一个hook。 它的名字以“use”开头(这是Hooks的规则之一 - 它们的名字必须以“use”开头)。

useState hook 的参数是 state 的初始值返回一个包含两个元素的数组:当前state和一个用于更改state 的函数。

类组件有一个大的state对象,一个函数this.setState一次改变整个state对象。

函数组件根本没有状态,但useState hook允许我们在需要时添加很小的状态块。 因此,如果只需要一个布尔值,我们就可以创建一些状态来保存它。

由于Hook以某种特殊方式创建这些状态,并且在函数组件内也没有像setState函数来更改状态,因此 Hook 需要一个函数来更新每个状态。 所以 useState 返回是一对对应关系:一个值,一个更新该值函数。 当然,值可以是任何东西 - 任何JS类型 - 数字,布尔值,对象,数组等。

Hooks 的特点

调用顺序规则 (它们每次必须以相同的顺序调用);

假设有以下这个组件:

function AudioPlayer() {
    
    
  const [volume, setVolume] = useState(80);
  const [position, setPosition] = useState(0);
  const [isPlaying, setPlaying] = useState(false);
  .....
}

它调用useState 3次,React 会在第一次渲染时将这三个 hook 放入 Hooks 数组中。

下次渲染时,同样的3个hooks以相同的顺序被调用,所以React可以查看它的数组,并发现已经在位置0有一个useState hook ,所以React不会创建一个新状态,而是返回现有状态。

这就是React能够在多个函数调用中创建和维护状态的方式,即使变量本身每次都超出作用域。

Hooks 的规则

自定义 hooks 函数只需要遵守规则 3 :它们的名称必须以“use”为前缀。

function AudioPlayer() {
    
    
  // Extract these 3 pieces of state:
  const [volume, setVolume] = useState(80);
  const [position, setPosition] = useState(0);
  const [isPlaying, setPlaying] = useState(false);

  // < beautiful audio player goes here >
}

创建一个专门处理这些状态的新函数,并使用一些额外的方法返回一个对象,以便更容易启动和停止播放,例如:

function usePlayerState(lengthOfClip) {
    
    
  const [volume, setVolume] = useState(80);
  const [position, setPosition] = useState(0);
  const [isPlaying, setPlaying] = useState(false);

  const stop = () => {
    
    
    setPlaying(false);
    setPosition(0);
  }

  const start = () => {
    
    
    setPlaying(true);
  }

  return {
    
    
    volume,
    position,
    isPlaying,
    setVolume,
    setPosition,
    start,
    stop
  };
}

这样提取状态的一个好处是可以将相关的逻辑和行为组合在一起。可以提取一组状态和相关事件处理程序以及其他更新逻辑,这不仅可以清理组件代码,还可以使这些逻辑和行为可重用。

通过在自定义hooks中调用自定义hooks,可以将hooks组合在一起。

hooks只是函数,当然,函数可以调用其他函数。

Hooks 提供了一种新的方式来处理React中的问题,其中的思想是很有意思且新奇的。

猜你喜欢

转载自blog.csdn.net/Menqq/article/details/111825252