NextJS中如何在useEffect中更新getInitialProps获取的初始数据以实现10秒定时刷新
getInitialProps and useEffect Hey there! The problem you're hitting is that the data passed from getInitialProps is a component prop, and React doesn’t let you mutate props directly. To fix this, you’ll need to use React’s useState hook to manage your data state—this way, you can update it whenever your periodic API call completes. Here’s a step-by-step solution:
Step 1: Import Required Hooks
First, make sure you import useState and useEffect from React (if you haven’t already):
import { useState, useEffect } from 'react'; import axios from 'axios';
Step 2: Initialize State with Initial Data
In your component, set up a state variable using the initial data from getInitialProps as the starting value:
export default function TvApp({ initialData }) { // Use useState to manage the mutable data state const [tvData, setTvData] = useState(initialData); // ... rest of your code }
Step 3: Set Up Periodic API Call in useEffect
Update your useEffect to fetch data every 10 seconds, and use setTvData to update the state when the request succeeds. Don’t forget to clear the timer when the component unmounts to avoid memory leaks:
useEffect(() => { // Define a reusable function to fetch updated data const fetchUpdatedData = async () => { try { // Make sure lineId is accessible here (same as in getInitialProps) const response = await axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`); // Update state with the new data setTvData(response.data); } catch (error) { console.error('Failed to fetch data:', error.response?.data || error.message); } }; // Fetch data immediately when the component mounts fetchUpdatedData(); // Set up the interval to fetch data every 10 seconds const timer = setInterval(fetchUpdatedData, 10000); // Clean up the interval when the component unmounts return () => clearInterval(timer); }, [lineId]); // Add lineId as a dependency if it can change dynamically
Step 4: Update Render Logic to Use State
Finally, adjust your JSX to use the tvData state variable instead of the original prop:
return ( <div className={styles.container}> <h2 className={styles.bigAmount}> {tvData.thirdScreen[0]?.AMOUNT} {/* Optional chaining is cleaner for null/undefined checks! */} </h2> </div> );
Full Updated Code
Here’s the complete code putting it all together, including the getInitialProps part:
import { useState, useEffect } from 'react'; import axios from 'axios'; import styles from './TvApp.module.css'; TvApp.getInitialProps = async (ctx) => { // Ensure you're retrieving lineId correctly (likely from ctx.query) const { lineId } = ctx.query; const res = await axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`); return { initialData: res.data }; }; export default function TvApp({ initialData }) { const [tvData, setTvData] = useState(initialData); // Pass lineId as a prop or retrieve it the same way as in getInitialProps const { lineId } = /* Your lineId source here */; useEffect(() => { const fetchUpdatedData = async () => { try { const response = await axios.get(`http://192.168.1.2:8090/api/tv_app/:${lineId}`); setTvData(response.data); } catch (error) { console.error('Data fetch error:', error.response?.data || error); } }; fetchUpdatedData(); const timer = setInterval(fetchUpdatedData, 10000); return () => clearInterval(timer); }, [lineId]); return ( <div className={styles.container}> <h2 className={styles.bigAmount}> {tvData.thirdScreen[0]?.AMOUNT} </h2> </div> ); }
Quick Notes:
- Optional Chaining: I replaced your manual null check with
?.—it’s a cleaner, more concise way to handle cases wherethirdScreen[0]might be undefined. - LineId: Double-check that
lineIdis accessible in bothgetInitialPropsand the component (you can pass it as a prop fromgetInitialPropsif needed). - Dependency Array: Adding
lineIdto theuseEffectdependency array ensures that iflineIdchanges, the interval will reset and fetch data for the new ID automatically.
内容的提问来源于stack exchange,提问作者ilvthsgm

