最初,如果手动输入的链接错误(例如:
"/characters/test"
),它可以工作,但如果正确,它仍然会重定向到错误 404。如果从 Character
组件单击链接,则它可以正常工作。这意味着无论我在浏览器上手动放置什么链接,都会导致错误 404。
我一直在尝试在
CharacterCard
组件上实现错误 404 重定向,方法是比较传递的 id - 'name'(如 useParams
)并将其与传递的另一个组件中的 characterId 列表进行比较(如果匹配) ,那么就可以正常渲染了,如果没有的话,就会重定向到错误404。
由于我使用的是 React-Router v6,据我所知,我无法正常传递 props。经过一番研究,我发现我可以使用
Link
状态将数据传递到它链接到的另一个组件,并使用 useLocation
获取传递的数据。我成功地将数据传递给组件,但随后导致了我上面提到的问题。
人物
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { PuffLoader } from "react-spinners";
const API_URL = 'something.somethin.com';
const CDN_URL = 'something2.somethin2.com';
export const Characters = () => {
const [characters, setCharacters] = useState([]);
const [isLoaded, setIsLoaded] = useState(false);
const validCharacterIds = characters.map((character) => character.id);
const getCharacters = async () => {
try {
const response = await fetch({API_URL});
const charactersData = await response.json();
const characterDetailsData = await Promise.all(
charactersData.map(async (character) => {
const characterDetails = await getCharacterDetails(character);
return characterDetails;
})
);
setCharacters(characterDetailsData);
console.log('characterDetaildata: ', characterDetailsData);
} catch (error) {
console.log("Error fetching Characters:", error);
}
};
const getCharacterDetails = async (character) => {
//code for getCharacterDetails
setIsLoaded(true);
return { ...characterDetailsData, id:character, icon: imageData };
};
useEffect(() => {
getCharacters();
document.title = "Characters | Website Title"
}, []);
return (
<div className='w-full py-[3rem] px-4 bg-white'>
//Character Card that when clicked opens CharacterCard Component
<div className='w-[500px] md:w-[1200px] mx-auto grid grid-cols-1 md:grid-cols-5 gap-5'>
{isLoaded ? (
(characters.length > 0) ? (
characters.map((character) => (
<Link key={character.name} to={`/characters/${character.id}`} state={{charIds: validCharacterIds}} className='w-full shadow-xl flex flex-col my-4 rounded-lg hover:scale-105 duration-300'>
<div className={
character.rarity === 4
? "bg-gradient-to-b from-[#5e5789] to-[#9c75b7]"
: character.rarity === 5
? "bg-gradient-to-b from-[#945c2c] to-[#b27330]"
: ''
}>
<img className='w-[300px] h-[250px] object-cover' src={character.icon} alt={character.name + ' Icon'} />
</div>
<div>
<h4 className='text-2xl font-bold text-center py-8'>{character.name}</h4>
</div>
</Link>
))
) : (
<div className='empty'>
<h2>No Characters Found!</h2>
</div>
)
) : (
<div className="flex justify-center items-center">
<PuffLoader color="#36d7b7" />
</div>
)}
</div>
</div>
);
};
人物卡
import React, { useEffect, useState } from 'react';
import { useNavigate, Navigate, useParams, useLocation } from 'react-router-dom';
import { PuffLoader } from 'react-spinners';
import Carousel from './Carousel';
const CDN_URL = 'somethin.somethin.com';
const API_URL = 'somethin2.somethin2.com';
export const CharacterCard = () => {
const [characterDetails, setCharacterDetails] = useState(null);
const navigate = useNavigate();
const { name } = useParams();
const location = useLocation();
let validCharIds = location.state;
console.log(location);
const getCharacterDetails = async (characterName) => {
//rest of the api fetch goes here
};
useEffect(() => {
const checkValidCharId = async () => {
if (!validCharIds || !validCharIds.charIds || !validCharIds.charIds.includes(name)) {
// Redirect to error 404 if the name is not in the validCharIds array or empty
navigate('*');
console.log('error 404');
} else {
// Fetch character details only if the name is valid
await getCharacterDetails(name);
}
};
checkValidCharId();
}, [name, validCharIds, navigate]);
if(characterDetails) {
return (
//Render component normally
);
}
else {
return (
<div className='flex justify-center items-center'>
<Navigate to='*'/>
</div>
)
}
};
您面临的问题可能与您在 Link 组件中使用 state 属性的方式有关。您可以使用不同的方法将数据传递到CharacterCard 组件,而不是依赖Link 组件的state 属性。您可以更新 Link 组件的 to 属性,将角色 id 作为参数包含在路由中:
<Link key={character.name} to={`/characters/${character.id}?charIds=${validCharacterIds.join(',')}`} className='w-full shadow-xl flex flex-col my-4 rounded-lg hover:scale-105 duration-300'>
这样,您就可以将 charId 作为查询参数传递到 URL 中。然后,在CharacterCard组件中,您可以使用useParams检索此查询参数:
const { name } = useParams();
const charIds = new
URLSearchParams(useLocation().search).get('charIds')?.split(',');
useEffect(() => {
const checkValidCharId = async () => {
if (!charIds || !charIds.includes(name)) {
navigate('*');
console.log('error 404');
} else {
await getCharacterDetails(name);
}
};
checkValidCharId();
}, [charIds, name, navigate]);
这样,无论是点击链接还是手动输入,CharacterCard 组件中都应该有必要的数据,并且 404 重定向逻辑应该按预期工作。
路由路径参数始终是字符串类型。我怀疑
character.id
是一个非字符串值,并且在作为 name
路由路径参数传递时会被字符串化。
建议进行类型不敏感的比较。字符串到字符串很常见,因为它涵盖非数字字符串,例如
"0123456789abcdef"
,以及类似数字的字符串,例如5
vs "5"
。
// Create array of id strings
const validCharacterIds = characters.map(({ id }) => id).map(String);
// or const validCharacterIds = characters.map(({ id }) => String(id));
...
{isLoaded ? (
characters.length ? (
characters.map((character) => (
<Link
key={character.name}
to={`/characters/${character.id}`}
state={{ charIds: validCharacterIds }} // <-- pass array of id strings
className='....'
>
...
</Link>
))
) : (
<div className='empty'>
<h2>No Characters Found!</h2>
</div>
)
) : (
<div className="flex justify-center items-center">
<PuffLoader color="#36d7b7" />
</div>
)}
export const CharacterCard = () => {
const [characterDetails, setCharacterDetails] = useState(null);
const navigate = useNavigate();
const { name } = useParams(); // <-- name is string type
const location = useLocation();
const { charIds } = location.state || {};
...
useEffect(() => {
const checkValidCharId = async () => {
if (!charIds.includes(name)) {
// Redirect to error 404 if the name is not in the validCharIds array or empty
navigate('*');
} else {
try {
// Fetch character details only if the name is valid
setCharacterDetails(await getCharacterDetails(name))
} catch(error) {
// handle any errors
};
}
};
checkValidCharId();
}, [name, charIds, navigate]);
...
};