首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在事件处理程序中调用自定义钩子

在事件处理程序中调用自定义钩子
EN

Stack Overflow用户
提问于 2020-12-28 03:21:22
回答 1查看 5.7K关注 0票数 7

我有一个名为useFetchMyApi的自定义钩子,它包装了对API端点的提取调用。函数钩子接受一个参数,它包含在post主体中。数据数组输出取决于钩子参数。

在UI上,App只调用一次useFetchMyApi。单击处理程序将调用后续的useFetchMyApi来更新UI上的列表。

我的问题:

我不能在事件处理程序中调用useFetchMyApi,因为它违反了钩子的规则。

代码语言:javascript
运行
复制
import React, { useState, useEffect, useRef } from "react";
import "./styles.css";

const useFetchMyApi = (location = "") => {
  const [items, setItems] = useState([]);
  useEffect(() => {
    // let's stimulate the API call with a 2 seconds response time
    setTimeout(() => setItems([location, Math.random()]), 5000);
  }, [location]);
  return { items };
};

export default function App() {
  const locationSelect = useRef(null);
  const { items } = useFetchMyApi("mylocation1");
  const onButtonClicked = (event) => {
    const selectedLocation = locationSelect.current.value;
    // Call api and refresh items by location
    // Fix here??
    //useFetchMyApi(selectedLocation);
  };

  return (
    <div className="App">
      <select ref={locationSelect}>
        <option value="location1">Location 1</option>
        <option value="location2">Location 2</option>
      </select>
      <button onClick={onButtonClicked}>Refresh</button>
      <ul>
        {items.map((item) => (
          <li>{item}</li>
        ))}
      </ul>
    </div>
  );
}

https://codesandbox.io/s/stupefied-water-1o6mz?file=/src/App.js:0-1055

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-28 04:40:12

问题

  1. 我不能在事件处理程序中调用useFetchMyApi,因为它违反了钩子的规则.

正确的,反应钩只能从主体的功能部件和其他反应钩调用。不能有条件地调用它们,例如在异步回调或循环中。

如何刷新依赖于useFetchMyApi响应的项列表?

App中没有任何东西可以触发重发器来触发效果,从而触发效果的回调。

解决方案

您应该利用自定义useEffect钩子中的useFetchMyApi钩子的依赖性来刷新项目列表。添加一些本地组件状态来表示“当前”选定的位置。使用您的按钮的onClick回调来更新状态并触发一个重命名器,然后重新运行您的自定义钩子。

代码语言:javascript
运行
复制
const useFetchMyApi = (location = "") => {
  const [items, setItems] = useState([]);
  useEffect(() => {
    // let's stimulate the API call with a 2 seconds response time
    setTimeout(() => setItems([location, Math.random()]), 2000);
  }, [location]); // <-- effect callback triggers when location updates
  return { items };
};

function App() {
  const locationSelect = useRef(null);
  const [location, setLocation] = useState("mylocation1"); // <-- add state
  const { items } = useFetchMyApi(location); // <-- pass location value to hook

  const onButtonClicked = () => {
    const selectedLocation = locationSelect.current.value;
    setLocation(selectedLocation); // <-- update state, trigger rerender
  };

  return (
    <div className="App">
      <select ref={locationSelect}>
        <option value="location1">Location 1</option>
        <option value="location2">Location 2</option>
      </select>
      <button onClick={onButtonClicked}>Refresh</button>
      <ul>
        {items.map((item) => (
          <li>{item}</li>
        ))}
      </ul>
    </div>
  );
}

替代解

另一种解决方案是重写自定义的useFetchMyApi钩子,以返回要在单击处理程序中按需调用的回调,以执行获取和更新列表的操作。这里有一个简单的转换。注意,现在返回的fetch函数使用的是位置,而不是钩子调用。

代码语言:javascript
运行
复制
const useFetchMyApi = () => {
  const [items, setItems] = useState([]);

  // custom fetch function consumes location
  const locationFetch = (location = "") => {
    // let's stimulate the API call with a 2 seconds response time
    setTimeout(() => setItems([location, Math.random()]), 2000);
  };
  
  return [items, locationFetch]; // <-- return state and fetch function
};

export default function App() {
  const locationSelect = useRef(null);
  const [items, locationFetch] = useFetchMyApi(); // <-- destructure state and fetch function

  useEffect(() => {
    locationFetch("mylocation1");
  }, []); // <-- initial mounting fetch call

  const onButtonClicked = () => {
    const selectedLocation = locationSelect.current.value;
    locationFetch(selectedLocation); // <-- invoke fetch function
  };

  return (
    <div className="App">
      <select ref={locationSelect}>
        <option value="location1">Location 1</option>
        <option value="location2">Location 2</option>
      </select>
      <button onClick={onButtonClicked}>Refresh</button>
      <ul>
        {items.map((item) => (
          <li>{item}</li>
        ))}
      </ul>
    </div>
  );
}

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65472666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档