如何防止 React 页面渲染两次

how to prevent react page from rendering twice

提问人:Harish Mahi 提问时间:7/24/2023 最后编辑:Harish Mahi 更新时间:7/24/2023 访问量:83

问:

我正在使用 react 18 StrictMode,并且在从一个页面导航到另一个页面(使用路由器)时,应用程序中有一些页面,首先显示一个空页面,并在 2 3 秒后页面刷新并显示数据。

示例:当我导航到此页面时,页面中有饼图 空网格首先显示,之后页面重新加载和饼图显示

我尝试了几种方法来防止它 1.微调器使用 use state、useRef 检查和 Suspense CallBack,但没有任何效果。

这是我的示例代码

服务.js

import axios from 'axios';
//demo code
class Service {

  async fetchData1() {
    try {
      const response = await axios.get("https//some-end-point");
      return response.data;
    } catch (error) {
      console.log('Error retrieving data:'+ error);
    }
  }

  async fetchData2(){
      try {
        const response = await axios.get("https//some-end-point");
        return response.data;
      } catch (error) {
        console.log('Error retrieving data:'+ error);
      }
  }

}
export default new Service();

仪表板.js

import React, { useEffect, useState } from 'react';
import Service from '../services/Service';

const Dashboard = () => {
  const [BarData, setBarData] = useState([]);
  const [StatsData, setStatsData] = useState([]);
  const [PieData, setPieData] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data1 = await Service.fetchData1();
        const data2 = await Service.fetchData2();
        if (data1) setBarData(data1);
        if (data2) setStatsData(data2);
      } catch (error) {
        console.log('Error fetching data:' + error);
      }
      setIsLoading(false);
    };

    fetchData();
  }, []);

  setPieData([
    {
      label: 'Label A',
      value: StatsData['Total Data A'],
    },
    {
      label: 'Label B',
      value: StatsData['Total Data B'],
    },
  ]);

  const PieDataChart = {
    series: PieData.map(item => item.value),
    options: {
      chart: {
        type: 'pie',
        width: 300,
        height: 300,
      },
      dataLabels: {
        enabled: false,
      },
      labels: PieData.map(item => item.label),
      //some properties
    },
  };

  if (isLoading) {
    return (
      <div className="loader">
        <RingLoader color="#36D7B7" loading={true} size={100} />
      </div>
    );
  }

  return (
    <div className="page-container">
      {/* demo data*/}
      <div className="pieChart-Wrapper">
        <div className="pieChart">
          <ReactApexChart options={PieDataChart.options} series={PieDataChart.series} type="pie" />
        </div>
      </div>
    </div>
  );
};

export default Dashboard;

我只想渲染页面一次,以防止第一次重新加载时出现空渲染,请帮帮我。

注意:我在useEffect中添加了一些日志,当从另一个页面导航到此页面时,会发出一个请求,它返回undefined,几秒钟后,一个请求正在发出,这次它获取数据。

谢谢

reactjs react-hooks react-18 严格模式

评论

0赞 B-Brazier 7/24/2023
React Strictmode 将在开发模式下执行此操作。生成并部署到生产环境时不会发生这种情况。我最好的建议是在测试时暂时删除本地环境中的严格模式。
0赞 Harish Mahi 7/24/2023
在apache服务器中部署后,我只注意到了这个问题,在生产版本中也得到了同样的问题

答:

2赞 dev0717 7/24/2023 #1

它可能与 React StrictMode 功能有关。它是为了避免渲染阶段的副作用而故意引入的。但是页面仅在开发模式下呈现两次,而不是在生产模式下。

评论

0赞 Harish Mahi 7/24/2023
但我仅在生产版本(Apache 服务器)中发现了问题
0赞 Harish Mahi 7/25/2023
即使在开发中删除严格模式后,我也遇到了同样的问题 ReactDOM.render( <App />, document.getElementById('root') );
0赞 Starcc 7/24/2023 #2

这是我的解决方案,希望对你有所帮助

import React, { useEffect, useState } from 'react';
import Service from '../services/Service';

const Dashboard = () => {
  const [BarData, setBarData] = useState([]);
  const [StatsData, setStatsData] = useState([]);
  const [PieData, setPieData] = useState([
    {
      label: 'Label A',
      value: 0,
    },
    {
      label: 'Label B',
      value: 0,
    },
  ]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data1 = await Service.fetchData1();
        const data2 = await Service.fetchData2();
        if (data1) setBarData(data1);
        if (data2) setStatsData(data2);
      } catch (error) {
        console.log('Error fetching data:' + error);
      }
      setIsLoading(false);
    };

    fetchData();
  }, []);

  useEffect(() => {
    if (StatsData['Total Data A'] && StatsData['Total Data B']) {
      setPieData([
        {
          label: 'Label A',
          value: StatsData['Total Data A'],
        },
        {
          label: 'Label B',
          value: StatsData['Total Data B'],
        },
      ]);
    }
  }, [StatsData]);

  const PieDataChart = {
    series: PieData.map(item => item.value),
    options: {
      chart: {
        type: 'pie',
        width: 300,
        height: 300,
      },
      dataLabels: {
        enabled: false,
      },
      labels: PieData.map(item => item.label),
      //some properties
    },
  };

  if (isLoading) {
    return (
      <div className="loader">
        <RingLoader color="#36D7B7" loading={true} size={100} />
      </div>
    );
  }

  return (
    <div className="page-container">
      {/* demo data*/}
      <div className="pieChart-Wrapper">
        <div className="pieChart">
          <ReactApexChart options={PieDataChart.options} series={PieDataChart.series} type="pie" />
        </div>
      </div>
    </div>
  );
};

export default Dashboard;

评论

0赞 Harish Mahi 7/24/2023
兄弟,我在第一次导航时考虑路由问题,返回未定义,在返回数据后表示请求不完整。这是否会导致在生产模式下进行两次渲染?
0赞 Steve B 7/26/2023
你能解释一下这段代码的哪一部分实际上解决了这个问题吗?