React Hooks 特性

React Hooks 特性

React Hooks

1. React Hooks 概述

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

产生原因也是解决的问题

  1. 在组件之间复用状态逻辑很难,为了复用状态和修改状态的逻辑,开发者总结出了 render props 和 高阶组件最佳实践,即使这样用起来还是有些晦涩。
  2. 复杂组件变得难以理解,表现在同一个生命周期函数中往往包含不相干的逻辑,比如从网络获取数据,设置监听,移除监听等等。
  3. class 组件内 this 指向(绑定)多种处理方式,导致学习者难以理解。

总结

  1. 可以不用定义类(class)组件的情况下管理组件状态
  2. React Hooks 完全向后兼容,原来的类(class)组件不会移除。
  3. Hooks的知识和开发者以前使用React的知识没有冲突二者可以并行,所以大家不必焦虑之前的知识是否过时。

2. State Hook 的使用

State Hook 的概念

  1. State-“状态”,Hook-“钩子”。

  2. 当组件需要存储和管理状态时,需要启动一个“钩子”,将状态和管理状态的函数“钩入”到当前组件中。

  3. 如何启动一个引入状态的钩子?

    通过调用 useState() 函数

使用 useState() 实现状态管理步骤

  1. 导入 useState

    import React, { useState } from 'react'
    
  2. 调用 useState()

    参数:状态的初始值

    返回值:数组,包含两个元素。第一个是状态,第二个是修改状态的函数

  3. 解构调用 useState() 返回的数组

    const [count, setCount] = useState(0)
    
  4. 使用状态值,当前组件内可见

    <button onClick={handleCount}>按钮被点击了{count}次</button>
    
  5. 使用修改组件状态的函数,当前组件内可见

    const handleCount = () => {
        setCount(count + 1)
    }
    
    return <button onClick={handleCount}>按钮被点击了{count}次</button>
    

useState() 使用步骤总结

  1. 导入 { useState }
  2. 定义函数组件
  3. 获取状态数据和修改状态数据的函数( useState() )
  4. 修改状态数据

useState() 初始化其它数据类型

  1. 初始化类型为字符串

    const [msg, changeMsg] = useState("Hello React")
    
  2. 初始化类型为数组

    const [todos, changeTodos] = useState([
        { id: 1, todo: "React" },
        { id: 2, todo: "Vue" },
    ])
    
  3. 不推荐初始化使用对象,因为本身对象就是多个键值对,多个值的维护还是推荐使用多次调用 useState 即可

useState() 注意点

  1. 在使用修改状态函数的时候乱传值,会怎样?

  2. 在 UI (JSX 表达式)中,调用修改状态的函数会怎样?

    const handleCount = () => {
        setCount(count + 1)
    }
    return <button onClick={handleCount}>按钮被点击了{count}次</button>
    
    const handleCount = () => {
        setCount(count + 1)
    }
    return <button onClick={handleCount}>按钮被点击了{setCount(count + 1)}次</button>
    

类(class)组件和使用 useState() 创建的函数组件对比

类(class)组件 useState()
导入 React 导入 { useState }
定义类组件 定义函数组件
定义状态(constructor) 获取状态数据和修改状态数据的函数(useState())

3. Effect Hook 的使用

Effect Hook 的概念

  1. Effect-“效果、作用”,Hook-“钩子”。

  2. 当组件初始化完毕后,需要从网络获取数据或修改DOM时,需要启动一个钩子,去执行对应的操作。

  3. 如何启动一个获取网络数据或修改DOM的钩子?

    通过调用 useEffect() 函数

使用 useEffect() 实现标签 title 显示计数信息

  1. 导入 useEffect

    import React, { useEffect } from 'react'
    
  2. 调用 useEffect()

    参数:是一个函数,在这个函数中进行业务操作

  3. useEffect() 中传入的函数有返回值时要定义为一个函数,作为此次 “Effect” 要执行的清除操作

    useEffect(() => {
        document.title = `按钮被点击了${count}次`
        return () => {
            console.log("我们做了清理操作")
        }
    })
    

useEffect() 使用步骤总结

  1. 导入 { useState, useEffect }
  2. 定义函数组件
  3. 获取状态数据和修改状态数据的函数
  4. 直接在 useEffect() 的参数中定义一个函数,在这个函数中进行DOM操作即可

useEffect() 传入函数的返回值

  1. 在 useEffect() 参数中定义的函数,如果返回值是一个函数,则 React 会在组件卸载时执行此函数

  2. 作用是对 useEffect() 调用后,可能引入的全局事件监听或者计时器操作等提供一个清除的时机

    useEffect(() => {
        document.title = `按钮被点击了${count}次`
        // 引入一个计时器
        const timerId = setInterval(() => {
            console.log("我是一个每隔1秒执行一次的定时器,我的Id是:", timerId)
        }, 1000)
        // 返回一个清理函数
        return () => {
            console.log("此次按钮点击我们做了清理操作,清理定时器的Id是:", timerId)
            // 清除定时器
            clearInterval(timerId)
        }
    })
    

useEffect()总结

  1. 可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个生命周期函数的组合

  2. useEffect 的执行时机

    useEffect 会在每次渲染后都执行吗?是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它)你可能会更容易接受 Effect 发生在“渲染之后”这种概念,不用再去考虑"挂载"还是"更新"。react 保证了每次运行 Effect 的同时,DOM 都已经更新完毕

  3. useEffect() 传入方法调用返回的清除函数的执行时机

    React 何时清除 Effect?React 会在组件卸载的时候执行清除操作。正如之前学到的,Effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 Effect 之前对上一个 Effect 进行清除。我们稍后将讨论为什么这将助于避免 bug 以及如何在遇到性能问题时跳过此行为

4. Context Hook 的使用

Context Hook 的概念

  1. useContext 让你不使用组件嵌套就可以直接使用Provider中传入的value属性的值
  2. 通过调用 useContext() 函数

使用useContext()

  1. 导入 useContext

    import React, {useContext} from 'react'
    
  2. 使用 React.createContext() 创建的 Context

  3. 调用 useContext()

    参数:第二步创建的 Context

    <div>
        <p>{useContext(ThemeContext)}</p>
    </div>
    

5. Hook 规则

第一条

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确

// ------------
// 首次渲染
// ------------
useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 nickname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题

// -------------
// 二次渲染
// -------------
useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
useEffect(persistForm)     // 2. 替换保存 form 的 effect
useState('Poppins')        // 3. 读取变量名为 nickname 的 state(参数被忽略)
useEffect(updateTitle)     // 4. 替换更新标题的 effect

// ...
// 
上一篇:三、Hook


下一篇:React学习 day-05