React Hook(自定义 Hook)

前沿

想写下react hooks ,一些基本资料,当然也可以看官网,我只是整理下

 react hooks 的官方基本介绍可以看 React 的文档:https://reactjs.org/docs/hooks-intro.html

一、State Hook

以一个简单的计数器举例,使用 useState 这个 Hook:

import { useState } from ‘react‘;
function Example() {
  // Declare a new state variable, which we‘ll call "count"
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

上面的 useState 实际上就是一个 Hook,我们在函数组件中调用它来向它添加一些本地的 state,而 React 在 re-render 之前会保留这个 state。useState 返回两个内容:

  • 当前的 state 值
  • 一个允许更新 state 值的 function

可以从事件处理程序或者其他位置调用返回的 function,和类中的 this.setState 比较累色,只不过不会将新的 state 和旧的 state 合并在一起。(React 给过一个使用 useState 和 this.state 的比较的示例https://reactjs.org/docs/hooks-state.html

useState 的唯一参数是初始状态,在上面的例子中,初始 state 是 0,因为计数器从 0 开始。请注意,和 this.state 不同的是,这里的 state 不一定是对象,可以是随便需要的形式。而初始状态参数仅仅在第一次渲染的时候使用。

 

1、声明多个 state 变量

可以在单个组件中多次使用 state Hook:

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState(‘banana‘);
  const [todos, setTodos] = useState([{ text: ‘Learn Hooks‘ }]);
  // ...
}

数组结构语法允许给 useState 的声明的 state 变量赋予不同的名称,这些名称并不是 useState API 的一部分。相反,React 假定如果多次调用 useState,则在每次渲染期间,以相同的顺序执行。

2、什么是 Hook

Hook 是允许从功能组件 挂钩 React 的 state 和生命周期方法等功能。Hook 在类的内部不起作用——允许在没有类的情况下使用 React。(React 不建议全部重写组件,只是建议如果感兴趣 Hook,可以在新的组件中使用)

React 提供了一些像 useState 这样的内置 Hook,还可以创建自己的 Hook 以便于重用不同组件之间的状态行为。

 

二、Effect Hook

我们已经可以在 React 组件中进行数据请求、subscriptions 或者是手动更改 DOM。

这些操作都是称为 side effects,也就是副作用。因为它们会影响其他组件,并且在渲染过程中没有办法完成。

useEffect 增加了从功能组件执行副作用的功能。它与 React 类的 componentDidMountcomponentDidUpdate 和 componentWillUnmount 具有相同的效果,但是统一成了一个 API。可以在 Using the Effect Hool 文档中查找关于更多 useEffect 的内容。

例如,下面的组件在 React 更新 DOM 后设置文档标题:

import { useState, useEffect } from ‘react‘;
function Example() {
  const [count, setCount] = useState(0);
  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
当调用 useEffect 的时候,告诉 React 在刷新对 DOM 的更改后运行 effect 副作用方法。因为 副作用方法 是在组件中声明的,因此可以访问 props 和 state。

默认情况下, React 在每次渲染后执行 effect 方法 —— 包括第一次渲染。想查看和生命周期方法的比较,也可以在 Using the Effect Hool 文档中找到。

同时 effect 副作用方法可以通过返回函数指定如何 “清理” 它们。例如,下面组件使用效果来订阅好友的在线 state,并通过取消订阅来实现清理的目的:

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);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  if (isOnline === null) {
    return ‘Loading...‘;
  }
  return isOnline ? ‘Online‘ : ‘Offline‘;
}

 

在这个示例中,组件卸载或者是由于后面的 re-render 而重新执行副作用方法之前,React 会取消订阅 ChatAPI。当然,如果 props 传过来的 id 是没有变化的,也可以通过某种方式来跳过订阅和取消订阅的行为:https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

和 useState 一样,可以在组件中使用多个 useEffect

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...

Hooks 允许通过哪些部分相关(比如添加和删除订阅)来组织组件中的副作用,而不是基于生命周期方法进行强制拆分。

三、 Hooks 的规则

Hooks 是 JavaScript 方法, 但它们强加了两个额外的规则:

  • 只能在顶层调用 Hooks,不能再循环、条件或者是嵌套方法中调用 Hooks。
  • 仅在 React 功能组件中使用 Hooks。不能再常规的 JavaScript 方法中调用 Hook。

React 提供了一个 linter 插件 来自动执行这些规则。虽然这些规则可能会让开发者比较首先,但是对于 Hooks 的良好运行至关重要。

四、构建自己的 Hook

有时,可能会希望在组件之间重用一些 state 的逻辑,一般之前的做法都是通过高阶组件或者是 render props 来解决。自定义 Hook 能够做到这种需求,而不需要向 tree 中增加更多组件。

前面虽然介绍了 useState 和 useEffect 来订阅朋友的在线状态,如果还希望在另一个组件中重用订阅逻辑,首先需要将这个逻辑提取到一个名为 useFriendStatus 的自定义 Hook 中:

import { useState, useEffect } from ‘react‘;
function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });
  return isOnline;
}

 

这个方法参数是 friendID ,返回的是好友是否在线。

而现在可以在两个组件中直接使用这个 Hook:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return ‘Loading...‘;
  }
  return isOnline ? ‘Online‘ : ‘Offline‘;
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? ‘green‘ : ‘black‘ }}>
      {props.friend.name}
    </li>
  );
}

 

这些组件的状态是完全独立的,Hook 是重用有 state 逻辑的一种方式,而不是重用 state 本身。事实上,每次调用 Hook 都会有个完全隔离的状态。因此可以在一个组件中使用相同的自定义 Hook 两次。

自定义 Hook 更像是一种约定,而不是一种功能。如果函数的名字以 use 开头,并且调用了其他的 Hook,则就称其为一个自定义 Hook。useSomething 命名约定是为了 linter 插件在代码中查找错误。

五、其他的 Hooks

除了上面的 useState 和 useEffect 之外,还有一些其他不太常用的 Hook 也可能很有用。比如 useContext 允许订阅 React 上下文,不去引入嵌套。

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

而 useReducer 允许使用 reducer 管理复杂的组件 state:


function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

就简答的介绍下HOOK吧,在数据请求的时候还是用到很多的

 

React Hook(自定义 Hook)

上一篇:STM32CubeMX | 40 - 实时时钟RTC的使用(日历和闹钟)


下一篇:浏览器输入图片链接无法预览,变成直接下载,点击按钮无法下载文件