4.Hook.md

Hook

Hook赋予了我们, 不使用classComponent也可以使用组件上的特性。例如: 生命周期,state状态.

  1. useState: 返回一个数组, 数组包含两个元素, 1) 对应的默认值, 2) 更新值的函数
    1
    2
    3
    4
    5
    6
    // 引入
    import React, {useState} from 'react'

    const [location, setLocation] = useState('default Value')
    // 此时, location 为被跟踪的变量
    // setLocation 为设置Location的钩子函数

这个原则对所有的钩子函数使用
注意, 不要把钩子的引入放到if-else, for等循环语句中.
钩子生效最重要的是根据钩子初始化的顺序.例如vue中的生命周期, 有严格的执行顺序.使用了分支语句, 那么就可能导致问题的产生.

  1. 自定义组件钩子
    我们写的组件,之前是基于props的数据流去处理, 如果使用hook那么一切都变成了函数.也就代替了之前使用,Class组件构建页面的结构.

自定义钩子的步骤:

  • 引入useState系统钩子
    1
    import {useState} from 'react'
  • 定制入参
    注意了, 入参就是你初始化钩子的参数.比如例子里, 一个下拉框, 入参为:

labalName: label标签的内容

defaultValue: 下拉框的默认值

options: 下拉框的数据list

  • 规范出参
    对于出参,我们遵循系统提供的hook的范式, 第一个参数为变量,最后一个参数为该变量的setState

  • 在出参中,我们有该变量的setState, 那么我们怎么实现这个功能呢?答案是, 使用useState.
    useState, 其实就是, 传入一个变量,返回两个参数, 第一个参数是变量的值, 这个值可被跟踪, 也就是当我们调用第二个参数的函数时(也就是setState), 那么就会触发这个值的更新.从而实现了数据侦听.

  1. Effect钩子 对比生命周期的概念
    effect钩子与渲染过程是分开的.在第一次渲染的时候,effect是不会被触发的.

作用一: 调用服务

1
2
3
useEffect(() => {
pet.breeds('dog').then(console.log, console.error)
})

作用二: 更新数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
useEffect(() => {
// 一个useEffect体里面, 第二个入参非常重要,
// 第二个入参是一个数组, 这个数组的内容是, 在参数1中的匿名函数存在的依赖项
// 在该例子中,我们不传入animal那么, 当animal更新时, 不会触发这个钩子
// 也就是只在渲染后执行一次匿名函数, 之后修改不会再次更新

// 注意, 如果第二个参数不传的话, 会导致无限循环, 至于为什么?
// 在effect钩子中, 我们肯定回去改变某些数据, 而不传我们要侦听的依赖项
// 那么effect的行为就是默认监听所有变化, 这就导致了, 更新的时候触发effect, 但是呢在effect里又会触发更新
console.log('触发effect生命周期', animal)
// 明白了, 这段代码的意思是, 每次触发更新的时候, 先把值清空
setBreeds([])
setBreed('')
pet.breeds(animal).then(({breeds}) => {
const breedStrings = breeds.map(({name}) => name)
setBreeds(breedStrings)
}, console.error)
}, [animal, setBreed, setBreeds])

解读一下, effect本质上解决我们在首次渲染后, 需要做的事, 比如: 获取数据, 记住执行顺序就好, effect相当于一个promise, 在完成渲染后执行, 如果存在依赖, 那么还会再次触发.就那么简单, 没啥.