You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useEffect无法实时更新加密货币价格状态问题求助

问题分析与解决方案

你的核心问题是自定义hookuseDataApi仅在url变化时发起一次请求,没有定时轮询机制,所以服务器端数据更新后,页面无法同步获取最新价格。以下是具体的修改方案:


1. 修改自定义hook,添加定时刷新功能

给useDataApi增加定时轮询逻辑,支持指定间隔自动刷新数据,同时避免内存泄漏:

import { useState, useEffect, useRef } from "react";
import axios from 'axios';

const useDataApi = (initialUrl, initialData, refreshInterval = 0) => {
  const [data, setData] = useState(initialData);
  const [url, setUrl] = useState(initialUrl);
  const [isLoading, setIsLoading] = useState(false);
  const [isError, setIsError] = useState(false);
  const timerRef = useRef(null); // 保存定时器ID,用于清理

  // 封装请求逻辑
  const fetchData = async () => {
    setIsError(false);
    setIsLoading(true);

    try {
      const result = await axios(url);
      setData(result.data);
    } catch (error) {
      setIsError(true);
    }

    setIsLoading(false);
  };

  // 初始请求 + url变化时触发请求
  useEffect(() => {
    fetchData();
  }, [url]);

  // 定时刷新逻辑
  useEffect(() => {
    if (refreshInterval > 0) {
      // 每隔指定时间重新请求
      timerRef.current = setInterval(fetchData, refreshInterval);
    }

    // 组件卸载时清理定时器
    return () => {
      if (timerRef.current) clearInterval(timerRef.current);
    };
  }, [refreshInterval, url]);

  return [{ data, isLoading, isError }, setUrl];
};

export default useDataApi;

2. 调整Search组件,启用定时刷新

修正组件内的小问题,并传入刷新间隔(比如5秒):

import SearchInput from "../components/SearchInput";
import { useState } from "react";
import "../../src/App.css";
import useDataApi from "../Hooks/axisFetch";
import ArrowDownward from "@mui/icons-material/ArrowDownward";
import ArrowUpward from "@mui/icons-material/ArrowUpward";
import Container from "@mui/material/Container";
import Button from "@mui/material/Button";
import { auth, db } from "../auth/auth";
import { addDoc, collection, serverTimestamp } from "firebase/firestore";
import { useUserAuth } from "../auth/UserAuthContent";
import Star from "@mui/icons-material/Star";

const Search = () => {
  const { user } = useUserAuth(auth);
  const apiUrl = "https://financialmodelingprep.com/api/v3/quote/";
  const [query, setQuery] = useState(""); // 初始值改为字符串,符合输入框逻辑
  // 传入5000ms(5秒)作为刷新间隔,实现实时更新
  const [{ data, isLoading, isError }, doFetch] = useDataApi(
    `${apiUrl}BTCUSD?apikey=${process.env.REACT_APP_API_KEY}`,
    null,
    5000
  );

  const sendSymbol = async (event) => {
    event.preventDefault();
    if (query.trim() === "") {
      alert("Enter valid message");
      return;
    }
    const { uid, displayName } = auth.currentUser;
    await addDoc(collection(db, "stocksSymbol"), {
      text: query,
      name: displayName,
      createdAt: serverTimestamp(),
      uid,
    });
    setQuery("");
  };

  // 移除空的无用useEffect

  return (
    <Container>
      <h1 className="header"> CRYPTO CURRENCIES SEARCH</h1>
      <h3>You can search by company name, compnay stock shortcut</h3>

      <form
        onSubmit={(event) => {
          // 去掉[query]的数组包裹,避免URL格式错误
          doFetch(`${apiUrl}${query}?apikey=${process.env.REACT_APP_API_KEY}`);
          event.preventDefault();
        }}
      >
        <SearchInput
          type="text"
          value={query}
          onChange={(event) => setQuery(event.target.value)}
        />
        <Button variant="contained" size="small" type="submit">
          Search
        </Button>
      </form>

      <div className="listContainer">
        <ul className="list">
          {isError && <div>Something went wrong ...</div>}
          {isLoading ? (
            <div>Loading ...</div>
          ) : (
            <>
              {data &&
                data.map((item) => {
                  return (
                    <li key={item.id}>
                      <span>{item.symbol}</span>
                      <span>{item.price}</span>
                      <span>{item.name}</span>
                      <span> % {item.change}</span>
                      <>
                        {item.change < 0 ? (
                          <ArrowDownward style={{ color: "red" }} />
                        ) : (
                          <ArrowUpward />
                        )}
                      </>
                      {!user ? (
                        ""
                      ) : (
                        <button
                          style={{
                            border: "none",
                            background: "none",
                            color: "yellow",
                          }}
                          onClick={(event) => sendSymbol(event)}
                        >
                          <Star />
                        </button>
                      )}
                    </li>
                  );
                })}
            </>
          )}
        </ul>
      </div>
    </Container>
  );
};

export default Search;

3. 关键说明

  • 定时轮询逻辑会每隔指定时间重新请求数据,确保页面价格和服务器同步
  • 用useRef保存定时器ID,避免重复创建定时器,同时在组件卸载时清理,防止内存泄漏
  • 保留了原有url变化时的请求逻辑,不影响搜索功能的正常使用

内容的提问来源于stack exchange,提问作者Omar Al

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 02:45:13