【问题标题】:Using A React Custom Hook With Side Effects For Event Handling (e.g. OnClick)使用带有副作用的 React 自定义 Hook 进行事件处理(例如 OnClick)
【发布时间】:2021-06-16 00:21:45
【问题描述】:

我在尝试使用自定义挂钩处理 OnClick 事件时遇到以下问题:

点击 OnClick 时,应发送 API 请求,并根据响应更新状态。

处理此问题的一种方法是在我的组件内部(或外部)简单地创建一个异步函数,用于获取数据并进行处理。这可以工作,但这种方法不允许我使用我的自定义钩子(例如 useFetch)。它也不允许我使用 useEffect,这是处理副作用的推荐方法。

另一种方法是使用自定义挂钩来处理点击。我会在我的功能组件主体的开头调用我的自定义钩子,然后自定义钩子可以返回一些可以用作 OnClick 处理程序的函数。但是该函数将无法使用 useEffect(因为 useEffect 只能从挂钩中调用),所以我不知道如何处理。

这似乎是一种常见的情况,但到目前为止我找不到任何好的解决方案。

提前致谢

【问题讨论】:

  • 你能发布一些代码以便我们更好地理解吗?当用户点击按钮时会发生什么? useEffect 仅在状态发生变化时触发,如果提供了 set 函数,则可以将相同的状态存储在自定义钩子中。
  • 我已经完成了一项工作,但我不能 100% 确定这可能是一个解决方案或尊重每个行为codeSandBox 可能这会帮助您找到实现它的方法
  • Tanato 的代码与此处的 antoineso 的代码非常相似。 @antoineso,您的解决方案看起来很棒。如果您将其发布为答案,我会接受。
  • @Rf Qm 感谢您的反馈。我已经发布了答案。

标签: javascript reactjs react-hooks


【解决方案1】:

对于您的自定义钩子useFetch,您可以执行以下操作:

useFetch.js

import { useEffect, useRef, useState } from "react";
const useFetch = (isTrig) => {
  const isEmpty = (data) => {
    return Object.keys(data).length === 0;
  };
  const [pokemons, setPokemons] = useState(null);
  const firstUpdate = useRef(true);
  const offset = useRef(0); // this is only to show you that you make a new fectch on every onClick call
  useEffect(() => {
    if (firstUpdate.current) {
      firstUpdate.current = false;

      return;
    }
    fetch(
      `https://pokeapi.co/api/v2/pokemon/?limit=10&offset=${offset.current}`
    )
      .then((response) => response.json())
      .then((data) => (isEmpty(data) ? null : data.results))
      .then((resPokemon) => setPokemons(resPokemon));
    offset.current += 10;
  }, [isTrig]);

  return pokemons;
};

export default useFetch;


在这个自定义钩子中,您使用了来自钩子 api useEffect、useState 和 useRef 的 3 个钩子。
usffect 参数中的 isTrig 在此示例中是一个布尔值,但您可以传递任何您想要的值,只要值更改以“触发”请求,例如您可以传递一个 id 并将其插入到请求中。 useRef 用于避免在传递给组件中的变量时启动请求。 您可以在组件中像这样调用 useFetch:
App.js

import "./styles.css";
import { useState } from "react";
import useFetch from "./useFetch";
export default function App() {
  const [isTrig, setIsTrig] = useState(false);
  const pokemons = useFetch(isTrig);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => setIsTrig((prev) => !prev)}>Fetch Pokemon</button>
      {pokemons && pokemons.map((p) => <div key={p.name}>{p.name}</div>)}
    </div>
  );
}

您可以在此处找到一个工作示例:

【讨论】:

    【解决方案2】:

    好吧,你的 useFetch 不应该关心按钮的点击或状态管理。 useFetch 应该只从 API 获取数据并返回响应。我强烈推荐react-query,但如果你不能使用它,你至少可以从他们的 API 中获得启发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-24
      • 2019-11-20
      • 2021-01-21
      • 2020-02-11
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 2020-04-09
      相关资源
      最近更新 更多