我正在使用 TypeScript 开发一个 React 应用程序,用于显示商店的卡片。我从一个 API 获取这些卡的数据,还需要从另一个 API 检索每张卡的其他信息,例如库存和价格。我的问题在于实现允许用户在将卡片显示在页面上之前按库存和价格对卡片进行排序的功能。但是,由于股票和价格信息是在卡片呈现后异步获取的(在 Card.tsx 中,我将结果与我的商店、股票和价格中的数据连接起来),我无法对它们进行正确排序。 我现在正在考虑两种可能的解决方案:
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { useAuth } from "../components/AuthContext";
import Cart from "../components/cart";
import Card from "../components/card";
import { useNavigate } from "react-router-dom";
const Search = () => {
const [results, setResults] = useState([]);
const { search } = useLocation();
const query = new URLSearchParams(search).get("query");
const { user, fetchLatestUserDetails } = useAuth();
const [noResults, setNoResults] = useState(false); // New state to track "no results" condition
const [filterInStock, setFilterInStock] = useState(true);
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(0);
const pageSize = 10; // New constant to define the number of items per page
useEffect(() => {
fetchLatestUserDetails().catch(console.error);
}, []);
const applyFilters = () => {
const basePath = filterInStock ? "/stock/search" : "/search";
const searchQuery = query ? `?query=${query}` : "";
navigate(`${basePath}${searchQuery}`);
};
useEffect(() => {
const fetchData = async () => {
const response = await fetch(
`https://api.scryfall.com/cards/search?unique=prints&include_multilingual=true&q=${query}`
);
const data = await response.json();
if (data.code === "not_found") {
// Check if the response indicates no results
setNoResults(true); // Set noResults to true if no results were found
setResults([]); // Ensure results is empty
} else {
// delete all data that has lang different from "en" or "es"
data.data = data.data.filter(
(card: { lang: string }) => card.lang === "en" || card.lang === "es"
);
console.log(data.data.length);
setTotalPages(Math.ceil(data.data.length / pageSize)); // Calculate total pages
//if data.data.length is 0, set noResults to true
if (data.data.length === 0) {
setNoResults(true);
setResults([]);
} else {
setResults(data.data); // Set the results if found
setNoResults(false); // Reset noResults to false
}
}
};
if (query) {
fetchData().catch(console.error);
}
}, [query, currentPage]);
const goToNextPage = () => {
setCurrentPage((prev) => (prev < totalPages ? prev + 1 : prev));
};
const goToPrevPage = () => {
setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev));
};
return (
<div className="searchpage">
<div className="filters">
<h1>Filtros</h1>
<div>
<input
type="checkbox"
id="stockCheckbox"
checked={filterInStock}
onChange={(e) => setFilterInStock(e.target.checked)}
/>
<label htmlFor="stockCheckbox">En Stock</label>
</div>
{/* Add Apply Filters Button */}
<button onClick={applyFilters}>Aplicar Filtros</button>
</div>
<div className="search-content">
{noResults ? (
<h3>No se encontraron resultados para: {query}</h3>
) : (
<div>
<h3>Resultados de busqueda para: {query}</h3>
<div className="order-buttons">
<div>
<button onClick={goToPrevPage}>Anterior</button>
<span>{currentPage}</span>
<button onClick={goToNextPage}>Siguiente</button>
</div>
</div>
<ul>
{results
.slice((currentPage - 1) * pageSize, currentPage * pageSize)
.map(
(
// its posible that some properties return null, so you can use the optional chaining operator to avoid errors
card: {
id: string | null;
name: string | null;
mana_cost: string | null;
colors: Array<any> | null;
set_name: string | null;
lang: string | null;
},
index: number
) => (
// style list so it doesn't have bullets
<li key={index} style={{ listStyle: "none" }}>
{card &&
card.id &&
card.name &&
card.set_name &&
card.lang && (
<Card
id={card.id}
name={card.name}
set_name={card.set_name}
lang={card.lang}
/>
)}
</li>
)
)}
</ul>
</div>
)}
</div>
<div>
{user ? (
<Cart items={user.cart} userConnected={true} />
) : (
<Cart items={null} userConnected={false} />
)}
</div>
</div>
);
};
export default Search;
如前所述,我已经尝试过两种可能的解决方案,但无法使它们发挥作用。 不知道有没有更好的办法
一些值得探索的想法: