useState,Hooks

92 阅读2分钟

1. 为什么要Hooks?

有了hooks,就可以不用class了,所有的组件都可以是function,hooks让function无状态组件有了状态。

class 带来的麻烦

用class创建react组件时,this指向是一件很棘手的事情,为了保证this指向正确,我们经常需要写: this.handleClick = this.handleClick.bind(this),或者是: <button onClick = {() => this.handleClick(e)>

2. State Hooks

import { useState } from 'react';

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

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

声明状态变量

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

useState函数接收的参数是状态初始值(initial state),它返回一个数组,数组第[0]项是当前状态值,第[1]项是可以改变状态值的函数。

也就是声明了一个状态变量count,把它的初始值设为0,同时提供了一个可以更改count的函数setCount。

假如一个组件有多个状态

  1. useState可以多次调用
function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

  1. useState的初始值可以多样

useState接收的初始值没有规定一定要是string/number/boolean这种简单数据类型,它完全可以接收对象或者数组作为参数。

react 怎么保证多个useState相互独立?

答案是,react是根据useState出现的顺序来定的。

2. Effect Hook

我们写的有状态组件,通常会产生很多的副作用(side effect),比如发起ajax请求获取数据,添加一些监听的注册和取消注册,手动修改dom等等。

我们之前都把这些副作用的函数写在生命周期函数钩子里,比如componentDidMountcomponentDidUpdatecomponentWillUnmount。而现在的useEffect就相当与这些声明周期函数钩子的集合体。

useEffect 解绑一些副作用

当我们在componentDidMount里添加了一个注册,我们得马上在componentWillUnmount中,也就是组件被注销之前清除掉我们添加的注册,否则内存泄漏的问题就出现了。

import { 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);
    // 一定注意下这个顺序:告诉react在下次重新渲染组件之后,同时是下次调用ChatAPI.subscribeToFriendStatus之前执行cleanup
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

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

这种解绑的模式跟componentWillUnmount不一样。

componentWillUnmount只会在组件被销毁前执行一次而已,而useEffect里的函数,每次组件渲染后都会执行一遍,包括副作用函数返回的这个清理函数也会重新执行一遍。

按照以前,如果props.friend.id变了,就要添加componentDidUpdate来处理。

useEffect没有这个问题:

1.页面首次渲染
2.替friend.id=1的朋友注册

3.突然friend.id变成了2
4.页面重新渲染
5.清除friend.id=1的绑定
6.替friend.id=2的朋友注册
...