React实现宝可梦详情页动态路由:单文件适配多URL
宝可梦网站动态路由实现方案
1. App.jsx:配置动态路由
移除重复的BrowserRouter(createBrowserRouter搭配RouterProvider是React Router v6的正确用法),将固定的/pikachu路由替换为动态路由:pokemonName,让所有宝可梦名称的路径都能匹配到Pokemon组件:
import React from "react"; import Pokemons from "./Pokemons"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; import Pokemon from "./Pokemon"; function App() { const router = createBrowserRouter([ { path: "/", element: <Pokemons />, }, { path: "/:pokemonName", // 动态路由参数,匹配任意宝可梦名称 element: <Pokemon />, }, ]); return ( <div> <RouterProvider router={router} /> </div> ); } export default App;
2. Pokemons.jsx:生成动态跳转链接
把固定的Link目标改成对应宝可梦的名称,同时删除无用的routerPath状态:
import React, { useEffect, useState } from "react"; import "./App.css"; import { Link } from "react-router-dom"; function Pokemons() { const [pokemonDetails, setPokemonDetails] = useState([]); useEffect(() => { async function fetchData() { const response = await fetch( "https://pokeapi.co/api/v2/pokemon?limit=20" ); const data = await response.json(); setPokemonDetails( await Promise.all(data.results.map((p) => fetchPokemonDetails(p.url))) ); } fetchData(); }, []); async function fetchPokemonDetails(url) { const response = await fetch(url); const data = await response.json(); return data; } return ( <div> <h2>Pokemony</h2> <div id="pokemony"> {pokemonDetails.map((element, index) => ( <div className="jedenBlok" key={index}> <h2 id={"Napis " + element.name} className="pokemoN"> {element.name} </h2> <img src={element.sprites.front_default} alt={`Pokemon ${index + 1}`} id={"Pokemon " + element.name} className="pokemon" /> {/* 动态生成对应宝可梦的跳转链接 */} <Link to={`/${element.name}`}>查看详情</Link> </div> ))} </div> </div> ); } export default Pokemons;
3. Pokemon.jsx:根据路由参数获取对应宝可梦详情
使用useParams获取路由中的宝可梦名称,只请求该宝可梦的接口数据,同时添加加载和错误状态提示:
import React, { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; function Pokemon() { const [pokemon, setPokemon] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const { pokemonName } = useParams(); // 获取路由中的宝可梦名称参数 useEffect(() => { async function fetchPokemon() { try { setLoading(true); // 根据路由参数请求对应宝可梦的详情 const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonName}`); if (!response.ok) throw new Error("宝可梦数据获取失败"); const data = await response.json(); setPokemon(data); setError(null); } catch (err) { setError(err.message); setPokemon(null); } finally { setLoading(false); } } fetchPokemon(); }, [pokemonName]); // 路由参数变化时重新请求数据 if (loading) return <div>加载中...</div>; if (error) return <div>错误:{error}</div>; if (!pokemon) return <div>未找到该宝可梦</div>; return ( <div> <Link to="/">返回首页</Link> <div> <h1>{pokemon.name}</h1> <img src={pokemon.sprites.front_default} alt={pokemon.name} /> <p>身高:{pokemon.height / 10}m</p> <p>体重:{pokemon.weight / 10}kg</p> <h3>属性:</h3> <ul> {pokemon.types.map((type, idx) => ( <li key={idx}>{type.type.name}</li> ))} </ul> </div> </div> ); } export default Pokemon;
内容的提问来源于stack exchange,提问作者tajgel
相关产品推荐
相关产品推荐

