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
相关产品推荐
相关产品推荐

