React hook 是16.8推出的新API,可以在不编写class的情况下使用state和其他特性。与无状态组件相比,hook函数组件提供了state以及处理副作用的API等等。

为什么要引入Hook?

在学习React hook之前,我很好奇为什么React团队为什么要引入hook,结合自己的理解以及从官网文档的描述,得出以下几点:

  • 在组件之间复用状态逻辑很难:在没有hook之前,React只能通过 render props高阶组件 来共享组件之间的状态逻辑,但是这两种方式都改变了组件结构,使得代码难以理解。
  • 复杂组件变得难以理解: 组件常常在 componentDidMount 和 componentDidUpdate 中获取数据。但是,同一个 componentDidMount 中可能也包含很多其它的逻辑,如设置事件监听,而之后需在 componentWillUnmount 中清除。相互关联且需要对照修改的代码被进行了拆分,而完全不相关的代码却在同一个方法中组合在一起。
  • 难以理解的class: 使用class创建组件比较麻烦的是在事件绑定上,this指向需要手动绑定,如果忘记的话很容易产生bug。

React hook中最重要的几个函数是以下几个:

  • useState
  • useEffect

useState

useState是很重要的一个hook函数,主要是用来创建组件内部数据,以及设置组件内部定义的数据。

import {useState} from 'react'

function countExample (props){

    const [count,setCount] = useState(0)

    return(
         <button onClick={()=>SetCount(count+1)}> 
         <p>当前值为{count}</p>    
    )
}

useState函数可以接受一个参数,代表状态初始化的数据。它返回一个数组,数组的第0项是自定义初始值,第1项是设置这个初始值的方法。例如上面代码中,count代表一个自定义变量,初始值为0。当然这个变量可以由开发者自己定义名称,同理setCount也是由用户自定义,不过一般设置属性名称为在自定义属性名前面加set。

如果想要创建多个自定义属性值怎么办?

    function Example(){
        const [age, setAge] = useState(42);
        const [name, setName] = useState('banana');
        const [gender,setGender] = useState('男')
    }

useEffect

useEffect函数主要是处理一些副作用(接口请求、DOM操控、清除定时器等等),实际上可以看做是class组件中componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

useEffect函数有两个参数:

  • 第一个参数为副作用执行的回调函数,在回调函数里面主要处理一些副作用。
  • 第二个参数为一个数组,如果第二个参数为空,那么在每一个state变化时,都会执行副作用。如果为空数组,那么就相当于两次执行对比数组里面的属性,发现两次都为空数组,则不会更新副作用。数组里面可以传自定义属性,根据实际业务需求来判断当哪个属性发生变化后,再执行相应的副作用。
    import React, { useState, useEffect } from 'react'
    import { message } from 'antd';

    function Example() {

        const [count, setCount] = useState(0)

        useEffect(() => {
            message.info(`当前count值为${count}`;)  
        },[count])

        return (
            <div >
                <button onClick={() => setCount(count - 1)}>-</button>
                {
                    <b>当前count值为:{count}</b>
                }
                <button onClick={() => setCount(count + 1)}>+</button>
            </div>
        );
    }

除了以上执行componentDidMount,componentDidUpdate钩子外,useEffect函数里面可以通过返回一个函数来达到执行 componentWillUnmount 方法。


    import React, { useState, useEffect } from 'react'
    import { message } from 'antd';

    function Modal({ visible }) {
        useEffect(() => {
            message.success('show box')
            return () => {
                message.info('hide box')
            };
        }, [visible])
        return (
            <div style={{ width: '200px', height: '200px', background: 'red' }}>
            </div>
        )
    }

    export default function Effect() {
    const [visible, setVisible] = useState(true)

    return (
        <div >
            <button onClick={() => setVisible(!visible)}>setBox</button>
            {
                visible && <Modal visible={visible}></Modal>
            }
        </div>
    )
}

以上Modal子组件是根据父组件动态显示的,当Modal子组件卸载后会触发effect钩子函数里面的return函数,从而显示hide box。