Hooks

作者: 行走的蛋白质 | 来源:发表于2020-03-30 17:09 被阅读0次

一、React 为什么要搞 Hooks,React Hooks 帮我们解决了哪些问题 ?

1. 在组件之间复用状态逻辑很难
  • 比如 render props 和 高阶组件。但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解。这说明了一个更深层次的问题:React 需要为共享状态逻辑提供更好的原生途径。
  • 你可以使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用。Hook 使你在无需修改组件结构的情况下复用状态逻辑。
  • 使用 hook 其中一个目的就是要解决 class 组件中生命周期函数经常包含不相关的逻辑,但又把相关联的逻辑分离到了几个不同的方法中的问题
2. 复杂组件变的难以理解
  • 每个生命周期常常包含一些不相干的逻辑
  • 为了解决这个问题,Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分。你还可以使用 reducer 来管理组件的内部状态,使其更加可预测
3. 使用多个 Effect 实现关注点分离
  • 使用 Hook 其中一个目的就是要解决 class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题
  • Hook 允许我们按照代码的用途分离他们, 而不是像生命周期函数那样。React 将按照 effect 声明的顺序依次调用组件中的每一个 effect

二、什么是 Hook

  • Hook 是一些可以让你在函数组件里 勾入 React state 及生命周期等特性的函数
  • Hook 不能在 class 组件中使用,只能在 React 的函数组件中调用 Hook
  • 只能在函数最外层调用 Hook,不要再循环、条件判断、子函数中调用
  • Hook 是一种复用状态逻辑的方式,它不复用 state 本身,事实上 Hook 的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook

三、常用 hook 介绍

1、useState
  • 在这里 useState 就是一个 Hook
  • 通过在函数组件里调用它,来给组件里添加内部 state
  • React 会在重复渲染时,保留这个 state
  • useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其它地方调用这个函数
  • 它类似 class 组件的 setState 但是它不会将新的 state 和旧的 state 进行合并
  • useState 唯一的参数就是初始的 state 不同于 this.state 这里的 state 不一定是一个对象
  • 这个初始 state 只有在第一次渲染的时候被用到
import React, { useState } from 'react'

const Hooks01 = () => {
    const [count, setCount] = useState(0)

    return (

        <div>
            <p>{count} times</p>
            <button onClick={() => setCount(count + 1)}> click me </button>
        </div>
    )
}

export default Hooks01
2、useEffect
  • 它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
  • React 会在每次渲染的时候调用 useEffect 函数,包括第一次渲染的时候
  • 在组件卸载的时候调用 useEffect 的 return 函数
import React, { useState, useEffect } from 'react'

const Hooks02 = () => {
    const [count, setCount] = useState(0)
    
    // 相当于 componentDidMount 和 componentDidUpdate:
    useEffect(() => {
        document.title = `you click the btn ${count} times`
    })

    return (
        <div>
            <p>click me 02 { count } times</p>
            <button onClick={() => setCount(count + 2)}>click me 02</button>
        </div>
    )
}

export default Hooks02
  • 使用多个 Effect 实现关注点分离:通过使用 Hook,你可以把组件内相关的副作用组织在一起(例如创建订阅及取消订阅),而不要把它们拆分到不同的生命周期函数里
function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}
  • 每次更新的时候都要运行 Effect:此默认行为保证了一致性,避免了在 class 组件中因为没有处理更新逻辑而导致常见的 bug
// Mount with { friend: { id: 100 } } props
ChatAPI.subscribeToFriendStatus(100, handleStatusChange);     // 运行第一个 effect

// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange);     // 运行下一个 effect

// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一个 effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange);     // 运行下一个 effect

// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一个 effect
  • 通过跳过 Effect 进行性能优化:
    • 在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 componentDidUpdate 中添加对 prevProps 或 prevState 的比较逻辑解决
    • 如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可
  • 如果你要使用此优化方式,请确保数组中包含了所有外部作用域中会随时间变化并且在 effect 中使用的变量,否则你的代码会引用到先前渲染中的旧变量
  • 如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

四、自定义 hook

  • 自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook
  • 自定义 Hook 是一种自然遵循 Hook 设计的约定,而并不是 React 的特性
  • 自定义 Hook 是一种重用状态逻辑的机制(例如设置为订阅并存储当前值),所以每次使用自定义 Hook 时,其中的所有 state 和副作用都是完全隔离的
  • 自定义 Hook 解决了以前在 React 组件中无法灵活共享逻辑的问题

相关文章

网友评论

      本文标题:Hooks

      本文链接:https://www.haomeiwen.com/subject/txgvuhtx.html