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

React Router路由切换但组件不渲染问题求助(GitHub Explorer)

问题描述

我正在开发个人项目「GitHub Explorer App」,使用React + React Router技术栈。需求为:首页仅展示搜索栏,用户输入GitHub用户名后,跳转到对应/username路由并展示该用户的详细信息。目前遇到的问题是:输入用户名后路由地址正常变化,但Results组件并未渲染,仅在首页显示数据。已用BrowserRouter包裹App,普通路由(如/hey)可正常工作,但动态路由:userName无法正常渲染组件。

相关代码

App.js

import HomeScreen from "./pages/Home/HomeScreen";
import { Route, Routes } from "react-router-dom";
import Results from "./components/Results/Results";

function App() {
  return (
    <Routes>
      <Route path="/" element={<HomeScreen />}>
        <Route path=":userName" element={<Results />} />
      </Route>
      <Route path="/hey" element={<Results />} />
    </Routes>
  );
}

export default App;

SearchBar.js

import React, { useState, useMemo } from "react";
import styles from "./SearchBar.module.css";
import Loading from "../Loading/Loading";
import { useNavigate } from "react-router-dom";

function Hahh() {
  const [username, setUsername] = useState("");
  const [userData, setUserData] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [cache, setCache] = useState({});
  const navigate = useNavigate();

  const fetchData = (username) => {
    setIsLoading(true);
    fetch(`https://api.github.com/users/${username}`)
      .then((response) => response.json())
      .then((data) => {
        setUserData(data);
        setIsLoading(false);
        setCache((prevCache) => ({ ...prevCache, [username]: data }));
      })
      .catch((error) => {
        console.error(error);
        setIsLoading(false);
      });
  };

  const cachedData = useMemo(() => {
    if (cache[username]) {
      return cache[username];
    } else {
      return null;
    }
  }, [cache, username]);

  const handleSubmit = (event) => {
    event.preventDefault();
    navigate(`/${username}`);
    if (username) {
      if (cache[username]) {
        setUserData(cache[username]);
      } else {
        fetchData(username);
      }
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          placeholder="Enter a GitHub username"
          className={styles.SearchInput}
          type="text"
          value={username}
          onChange={(event) => setUsername(event.target.value)}
        />
        <button className={styles.SearchButton} type="submit">
          Search
        </button>
      </form>
      {isLoading && <Loading />}
      {cachedData && (
        <div className={styles.ResultContainer}>
          <h2>User Data</h2>
          <p>Name: {cachedData.name}</p>
          <p>Public Repos: {cachedData.public_repos}</p>
        </div>
      )}
      {userData && !cachedData && (
        <div className={styles.ResultContainer}>
          {" "}
          <h2>User Data</h2>
          <p>Name: {userData.name}</p>
          <p>Public Repos: {userData.public_repos}</p>
        </div>
      )}
    </div>
  );
}

export default Hahh;

HomeScreen.js

import React from "react";
import styles from "./HomeScreen.module.css";
import Logo from "../../assets/Hipo.svg";
import SearchBar from "../../components/SearchBar/SearchBar";

const HomeScreen = () => {
  return (
    <>
      <div className={styles.HomeScreen}>
        <div className={styles.ExplorerContainer}>
          <img className={styles.Logo} src={Logo} alt="GitHub Explorer Logo"></img>
          <div className={styles.ExplorerText}>GitHub Profile Explorer</div>
          <SearchBar />
        </div>
      </div>
    </>
  );
};

export default HomeScreen;

Results.js

import { useEffect, useState } from "react";
import { Outlet, useParams } from "react-router-dom";

function Results() {
  const { userName } = useParams();
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    const fetchUserData = async () => {
      try {
        const response = await fetch(
          `https://api.github.com/users/${userName}`
        );
        const data = await response.json();
        setUserData(data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchUserData();
  }, [userName]);

  if (!userData) {
    return <div>Loading...</div>;
  }
  console.log(userName);
  return (
    <div>
      <Outlet />
      <h1>{userData}</h1>
      <p>{userData.bio}</p>
      <img src={userData.avatar_url} alt="User Avatar" />
    </div>
  );
}

export default Results;

问题截图

  • 初始页面:初始页面
  • 输入用户名后:路由变化但组件未渲染路由变化但组件未渲染

解决方案

1. 修复路由结构问题

你把:userName设为HomeScreen的子路由,但HomeScreen中没有添加<Outlet />,导致子路由组件无法渲染。根据需求,跳转后应替换首页内容,需将:userName改为独立路由:

修改后的App.js:

import HomeScreen from "./pages/Home/HomeScreen";
import { Route, Routes } from "react-router-dom";
import Results from "./components/Results/Results";

function App() {
  return (
    <Routes>
      <Route path="/" element={<HomeScreen />} />
      <Route path="/:userName" element={<Results />} />
      <Route path="/hey" element={<Results />} />
    </Routes>
  );
}

export default App;

2. 移除SearchBar的首页数据渲染逻辑

当前SearchBar在提交后仍在首页展示数据,不符合跳转路由展示的需求,需删除这部分代码,仅保留搜索和跳转逻辑:

修改后的SearchBar.js(建议将组件名改为SearchBar保持语义一致):

import React, { useState } from "react";
import styles from "./SearchBar.module.css";
import Loading from "../Loading/Loading";
import { useNavigate } from "react-router-dom";

function SearchBar() {
  const [username, setUsername] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [cache, setCache] = useState({});
  const navigate = useNavigate();

  const handleSubmit = (event) => {
    event.preventDefault();
    if (!username) return;
    
    setIsLoading(true);
    if (cache[username]) {
      setIsLoading(false);
      navigate(`/${username}`);
    } else {
      fetch(`https://api.github.com/users/${username}`)
        .then((response) => response.json())
        .then((data) => {
          setCache(prev => ({...prev, [username]: data}));
          setIsLoading(false);
          navigate(`/${username}`);
        })
        .catch((error) => {
          console.error(error);
          setIsLoading(false);
        });
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          placeholder="Enter a GitHub username"
          className={styles.SearchInput}
          type="text"
          value={username}
          onChange={(event) => setUsername(event.target.value)}
        />
        <button className={styles.SearchButton} type="submit">
          Search
        </button>
      </form>
      {isLoading && <Loading />}
    </div>
  );
}

export default SearchBar;

3. 优化Results组件渲染逻辑

原组件直接渲染userData会显示[object Object],需改为渲染具体字段,同时增加错误和加载状态处理:

修改后的Results.js:

import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";

function Results() {
  const { userName } = useParams();
  const [userData, setUserData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUserData = async () => {
      setIsLoading(true);
      try {
        const response = await fetch(`https://api.github.com/users/${userName}`);
        if (!response.ok) throw new Error("用户不存在");
        const data = await response.json();
        setUserData(data);
        setError(null);
      } catch (error) {
        setError(error.message);
        console.error(error);
      } finally {
        setIsLoading(false);
      }
    };

    if (userName) fetchUserData();
  }, [userName]);

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误:{error}</div>;

  return (
    <div>
      <h1>{userData.name || userData.login}</h1>
      <p>{userData.bio || "未填写简介"}</p>
      <img 
        src={userData.avatar_url} 
        alt={`${userData.login}的头像`} 
        style={{width: '200px', borderRadius: '50%'}} 
      />
      <p>公开仓库数量:{userData.public_repos}</p>
    </div>
  );
}

export default Results;

4. 可选:全局缓存优化

若需在Results中复用缓存,可将缓存状态提升到App组件或使用React Context,实现SearchBar和Results共享缓存,避免重复请求。


内容的提问来源于stack exchange,提问作者krina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:57:03