【问题标题】:Why's my response being called more than once when the variable's passed down from top level App component?当变量从顶级 App 组件向下传递时,为什么我的响应被多次调用?
【发布时间】:2025-11-24 22:30:01
【问题描述】:

每当我通过 prop 将 App.js 中的 uploadsData 变量发送到 <Gallery data={uploadsData}/>} /> 组件时,它都会被多次调用。

此外,每当我将鼠标悬停在蓝色 ! 上时,我都会在屏幕截图中看到该警告。这意味着我永远无法正确访问此对象。

我怎样才能使它只执行一次,以便我可以以正确的方式访问对象?

我认为在useEffect()(第二个参数)中有一个[]作为依赖项会导致为它只执行一次铺平道路?

提前感谢您花时间阅读。我愿意接受任何形式的反馈,包括被认为是更好的做法的代码改进/更改

这里是App.js

import { useEffect, useState } from 'react';
import { BrowserRouter as Router, Switch, Route, useHistory} from 'react-router-dom';
import ReactDOM from 'react-dom';
import '../../sass/HomePage/homePage.scss';
import LoginRegister from "./LoginRegister/LoginRegister";
import Gallery from "./Gallery/Gallery";
import Cookies from 'js-cookie';

const App = () => {
    const [uploadsData, setUploadsData] = useState([]);
    let { push } = useHistory();
    let authToken = Cookies.get('token');

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

    function getUploads() {
        const headers = {
            "Accept": 'application/json',
            "Authorization": `Bearer ${authToken}`
        }

        axios.get('http://localhost:8005/api/get-uploads', {headers})
            .then(resp => {
                let uData = [...uploadsData,resp];
                setUploadsData(uData);
                if (authToken !== null) {
                    push('/gallery');
                } else {
                    console.log("User's NOT authenticated, returning to login view");
                    push('/');
                }
            }).catch(error => {
            console.log(error);
        })
    }

    return (
        <>
            <Switch>
                <Route exact path="/" component={LoginRegister} />
                <Route component={() => <Gallery data={uploadsData}/>} />
            </Switch>
        </>
    );
}

export default App;

if (document.getElementById('example')) {
    ReactDOM.render(<Router><App/></Router>, document.getElementById('example'));
}

这里是Gallery.js

import React from 'react';

const Gallery = (data) => {    
    return (
        <>    
            {console.log(data)}
        </>
    );
}

export default Gallery;

【问题讨论】:

    标签: javascript reactjs debugging


    【解决方案1】:

    这里是您在 Playground 中的代码副本,并附有一些解释:https://codesandbox.io/s/practical-sun-9cc1v?file=/src/App.js (有 react-router-dom v6 而不是 v5 - 无重大变化)

    import { useEffect, useState } from "react";
    import { Routes, Route, useNavigate } from "react-router-dom";
    import Gallery from "./Gallery";
    import axios from "axios";
    
    const App = () => {
      const [uploadsData, setUploadsData] = useState([]);
      let navigate = useNavigate();
    
      useEffect(() => {
        console.log("initial render");
        getUploads();
      }, []);
    
      function getUploads() {
        const headers = {
          Accept: "application/json"
        };
    
        axios
          .get("https://jsonplaceholder.typicode.com/todos/1", { headers })
          .then((resp) => {
            console.log("loading start");
            let uData = [...uploadsData, resp];
            setUploadsData(uData);
            console.log("navigate and re-render");
            navigate("/gallery");
            console.log("loading end");
          })
          .catch((error) => {
            console.log(error);
          });
      }
    
      return (
        <Routes>
          <Route exact path="/" element={<div />} />
          <Route path="gallery" element={<Gallery data={uploadsData} />} />
        </Routes>
      );
    };
    
    export default App;

    所以最初(从/ 开始时)我们只有一个渲染/控制台输出。 但是在第一次运行(/gallery)之后,我们已经有了 3 个渲染/控制台输出——据我所知,这是最初的问题。原因:

    • 初始渲染
    • setState 再触发一次渲染
    • /gallery 导航到/gallery 又引发了一次

    随意评论提到的代码块并检查控制台

    关于这里的最佳实践,有一个来自 react-router 和 remix https://stackblitz.com/github/remix-run/react-router/tree/main/examples/auth 的好例子。

    如果答案不够完整,请随时发表评论

    UPD:一个示例,无需重新渲染子组件,只需极少的更改代码andbox.io/s/flamboyant-archimedes-h0fhr?file=/src/App.js

    【讨论】:

    • 无论用户是否刷新页面和/或新登录,我只希望它只在 Gallery 组件中呈现一次和一次。这可能吗?
    • 是的,你可以拆分你的逻辑:检查包装器中的会话,如果有令牌 - 渲染路由,通过/gallery 你将获得画廊组件,在这个组件的逻辑内获取数据
    • 好的,试试看,谢谢!
    • codesandbox.io/s/flamboyant-archimedes-h0fhr?file=/src/App.js 这是一个改动很小的示例 1) 在响应之前不要渲染路由 2) 仅在必要时导航。请看一下 react-router 团队的示例。
    最近更新 更多