React Hook 学习记录

169 阅读3分钟

20210428学习更新

参考: Hook

Hook 是什么?

Hook 是一些可以让你在函数组件里“钩入” React state生命周期等特性的函数

例如,使用State Hook为函数组件“钩入” React state;使用Effect Hook 为函数组件“钩入”生命周期。

State Hook

// 传统的class使用state
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0  // 初始值
    }; 
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>  // 读取state
        // 使用setState更新count的值
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
// 使用hook
import React, { useState } from 'react';

function Example() {
  // 声明一个叫 “count” 的 state 变量。
  const [count, setCount] = useState(0);  // 设置初始值

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

补充:

  • useState 返回一个数组,第一个元素为变量,第二个元素为更新变量的函数。使用数据结构给返回值命名。
 const [fruit, setFruit] = useState('banana');
 //等同于
  var fruitStateVariable = useState('banana'); // 返回一个有两个元素的数组
  var fruit = fruitStateVariable[0]; // 数组里的第一个值
  var setFruit = fruitStateVariable[1]; // 数组里的第二个值
  • useState 唯一的参数是变量的初始值。

Effect Hook

Effect Hook 可以让你在函数组件中执行副作用操作。

什么是副作用?

任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。
而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。

参考: 函数式编程

useEffect Hook

如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。

// 在 React 对 DOM 进行操作之后,立即更新 document 的 title 属性
// 传统class
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

//需要在componentDidMount 和 componentDidUpdate 调用相同的方法
  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
// useEffect Hook
import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    document.title = `You clicked ${count} times`; // DOM更新完成后执行
  });

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

补充:

  • effect 发生在“渲染之后”这种概念,React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。
  • 如果effect 返回一个函数,React 将会在执行清除操作时调用它。React 会在组件卸载的时候执行清除操作。
 useEffect(() => {
    // do something
    // Specify how to clean up after this effect:
    return function cleanup() {  // 清楚函数
    // do something
    );
    };
  });
  • 使用多个 Effect 实现关注点(功能)分离。
  • useEffect的第二个参数可以决定哪些值发生变化时再执行第一个参数对应的函数。依次对数组中的值进行比较。如果数组中有多个元素,即使只有一个元素发生变化,React 也会执行 effect。

FC 是什么?

FC是FunctionComponent的简写, 这个类型定义了默认的 props(如 children)以及一些静态属性(如 defaultProps)。

// types\react\index.d.ts
    type FC<P = {}> = FunctionComponent<P>;

    interface FunctionComponent<P = {}> {
        (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
        propTypes?: WeakValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
    }

useEffect 的作用

参考文献:zh-hans.reactjs.org/docs/hooks-…

  • 发生在“渲染之后”,不用再去考虑“挂载”还是“更新”。
  • 可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
  • React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。
  • 每个 effect 都可以返回一个清除函数。
import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

  • 如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数