首页 > 解决方案 > 如何使用 onClick 从自定义 React 钩子 (API) 中获取数据并使用 TypeScript 将其显示在 Div 中?

问题描述

我是 TypeScript 甚至 React Hooks 的新手。我正在尝试从一个名为 的自定义钩子中连续获取数据,该钩子useFetch()接受一个字符串(URL)参数:

import { useEffect, useState } from "react";

export interface Payload {
  data: null | string,
  loading: boolean
}

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})

  useEffect(() => {
    setState(state => ({ data: state.data, loading: true }));
    fetch(url)
      .then(x => x.text())
      .then(y => {
        setState({ data: y, loading: false });
      });
  }, [url, setState])

  return state;
  }

export default useFetch;

我将该钩子导入App()

import React, { useState, useEffect } from "react";
import useFetch from './utils/useFetch'
import {Payload} from './utils/useFetch';

const App = () => {
  const [quote, setquote] = useState<Payload>({data: null, loading: true})
  const handleClick = () => setquote(data)

  const data = useFetch(
    "/api/rand"
  );

  return (
    <div>
      <h1>Quotes</h1>
      <button onClick={handleClick}>Get Quote</button>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;

在第一次加载应用程序时,它可以工作。单击按钮时,我得到数据(报价)。

预习

但是,当我多次单击它时,API 不会再次调用,新数据也不会通过。我相信我应该使用useEffect()react 钩子并保持状态(也许我错了),但到目前为止我所有的尝试都无济于事。任何帮助将非常感激。如果我弄清楚了,我肯定会回答这个问题。谢谢!

标签: javascriptreactjstypescriptreact-hooks

解决方案


看起来你在这里混合了两个想法。

您想连续获取数据吗?(持续的意思是一直,例如,周期性地,间隔地)

或者您想在安装组件时获取数据(当前发生)并且当用户点击“获取报价”按钮(当前不工作)时?

我会尽力帮助你。

连续/定期

尝试稍微更改设置。在 useFetch 内部执行以下操作:

import { useEffect, useState } from "react";

export interface Payload {
  data: null | string,
  loading: boolean
}

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})

  useEffect(() => {
    const interval = setInterval(() => {
        setState(state => ({ data: state.data, loading: true }));
        fetch(url)
          .then(x => x.text())
          .then(y => {
            setState({ data: y, loading: false });
          });
     }, 2000); // Something like 2s

     return () => {
        clearInterval(interval); // clear the interval when component unmounts
     }
  }, [url])

  return state;
  }

export default useFetch;

这将每 2 秒获取一次端点并更新状态变量,然后这将反映在应用程序中(或任何使用该钩子的地方)。

因此,您不再需要应用程序中的报价状态。此外,您不再需要 UI 中的按钮。

应用程序看起来像:

import React, { useState, useEffect } from "react";
import useFetch from './utils/useFetch'
import {Payload} from './utils/useFetch';

const App = () => {
  const quote = useFetch(
    "/api/rand"
  );

  return (
    <div>
      <h1>Quotes</h1>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;

在安装组件时获取数据(当前发生)并且当用户点击“获取报价”按钮时

那么我认为 useFetch 钩子并不是真正需要/适合的。这个应用程序可以使用一个钩子,但是将它转换成一个更简单的函数对我来说更有意义。我建议省略 useFetch 钩子。App 组件看起来像:

import React, { useState, useEffect, useCallback } from "react";

const App = () => {
  const [quote, setQuote] = useState<Payload>({data: null, loading: true})

  const handleGetQuote = useCallback(() => {
    setQuote(state => ({ data: state.data, loading: true }));
    fetch("/api/rand")
      .then(x => x.text())
      .then(y => {
        setQuote({ data: y, loading: false });
      });
  }, []);

  useEffect(() => {
    handleGetQuote();
  }, [handleGetQuote]);

  return (
    <div>
      <h1>Quotes</h1>
      <button onClick={handleGetQuote}>Get Quote</button>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;

推荐阅读