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

React组件挂载时不渲染数据,重渲染后正常的问题求助

问题:组件挂载时无数据显示,重渲染后才正常展示

我在完成GreatFrontEnd的任务,需要从Job API获取数据:先获取任务ID列表,再遍历ID获取对应的Job对象数组。现在遇到问题:组件挂载时没有数据显示,但修改代码触发重渲染(比如增删括号)后数据能正常展示。之前把两个请求放在独立的useEffect里能正常运行,现在想精简代码就出问题了,代码如下:

import React, { useState, useEffect } from 'react';

export default function App() {
  const [jobsIds, setJobIds] = useState(null);
  const [jobs, setJobs] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    getJobs();
    console.log(jobs)
}, []);

  const getJobIds = async () => {
     try {
      const idRes = await fetch(`https://hacker-news.firebaseio.com/v0/jobstories.json`);
      const jobIds = await idRes.json();
      setJobIds(jobIds);
    } catch (error) {
      console.error('Error fetching job IDs:', error);
    }
  }

  const getJobs = async () => {
    await getJobIds()
    
    try {
      setLoading(true);
      const jobsData = await Promise.all(
        jobsIds.map(async (id) => {
          const jobRes = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
          return await jobRes.json();
          
        })
       
      );
        setJobs(jobsData)
     
      setLoading(false);
    } catch (error) {
      console.error('Error fetching jobs:', error);
      setLoading(false);
    }
  };

  return (
    <>
    {loading? <p> Loading.... </p>: jobs.map((job) =>(
      <p> {job.title} </p>
  ))}
    </>
  );
}

问题根源

核心问题是React状态更新是异步的:你在getJobs里用await getJobIds()等待ID请求完成,但setJobIds(jobIds)只是触发状态更新,并不会立刻改变jobsIds的值。所以当你紧接着调用jobsIds.map时,jobsIds还是初始的null,这会导致Cannot read property 'map' of null的错误——虽然被try-catch捕获,但后续获取数据的逻辑直接中断,最终jobs还是空数组,所以组件挂载时没数据。

而当你修改代码触发重渲染时,jobsIds已经在第一次请求后被更新为有效数组,此时再次执行getJobs就能正常调用map获取数据了。

修复方案

方案1:直接返回ID数组,跳过状态存储

既然getJobIds的唯一作用是给后续请求提供ID,没必要把ID存在状态里,直接让函数返回ID数组即可,彻底避免状态异步更新的问题:

修改getJobIds:

const getJobIds = async () => {
  try {
    const idRes = await fetch(`https://hacker-news.firebaseio.com/v0/jobstories.json`);
    return await idRes.json(); // 直接返回ID数组
  } catch (error) {
    console.error('Error fetching job IDs:', error);
    return []; // 出错时返回空数组,避免后续map报错
  }
}

修改getJobs:

const getJobs = async () => {
  try {
    setLoading(true);
    const jobIds = await getJobIds(); // 直接拿到返回的ID数组
    const jobsData = await Promise.all(
      jobIds.map(async (id) => {
        const jobRes = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
        return await jobRes.json();
      })
    );
    setJobs(jobsData);
    setLoading(false);
  } catch (error) {
    console.error('Error fetching jobs:', error);
    setLoading(false);
  }
};

方案2:监听jobsIds状态变化(保留ID状态的场景)

如果后续需要用到jobsIds状态,可以把获取详情的逻辑放到监听jobsIds的useEffect里,确保ID更新后再请求数据:

useEffect(() => {
  const fetchJobs = async () => {
    if (!jobsIds) return; // ID为空时不执行
    try {
      setLoading(true);
      const jobsData = await Promise.all(
        jobsIds.map(async (id) => {
          const jobRes = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
          return await jobRes.json();
        })
      );
      setJobs(jobsData);
      setLoading(false);
    } catch (error) {
      console.error('Error fetching jobs:', error);
      setLoading(false);
    }
  };

  fetchJobs();
}, [jobsIds]); // 监听jobsIds变化,有值时执行请求

useEffect(() => {
  getJobIds(); // 挂载时先获取ID
}, []);

完整修复代码(方案1)

import React, { useState, useEffect } from 'react';

export default function App() {
  const [jobs, setJobs] = useState([]);
  const [loading, setLoading] = useState(false);

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

  const getJobIds = async () => {
    try {
      const idRes = await fetch(`https://hacker-news.firebaseio.com/v0/jobstories.json`);
      return await idRes.json();
    } catch (error) {
      console.error('Error fetching job IDs:', error);
      return [];
    }
  }

  const getJobs = async () => {
    try {
      setLoading(true);
      const jobIds = await getJobIds();
      const jobsData = await Promise.all(
        jobIds.map(async (id) => {
          const jobRes = await fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`);
          return await jobRes.json();
        })
      );
      setJobs(jobsData);
      setLoading(false);
    } catch (error) {
      console.error('Error fetching jobs:', error);
      setLoading(false);
    }
  };

  return (
    <>
      {loading ? <p> Loading.... </p> : jobs.map((job) => (
        <p key={job.id}> {job.title} </p> {/* 添加key避免React列表渲染警告 */}
      ))}
    </>
  );
}

内容的提问来源于stack exchange,提问作者Aidan McCormick-Buczko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 10:20:33