我是一名初级开发人员,我创建了一个饮酒游戏,一种“敢不敢喝”的游戏。我使用了带有 TypeScript、Drizzle 和 PostgreSQL 的 T3 Create 应用程序。
问题是我的应用程序获取一个值和卡片,但随后停止渲染它们。有时它在一张或两张卡后停止,有时它会增加到八张,然后它就停止渲染。我必须刷新网站才能再次工作。
我没有收到任何错误日志或任何东西;控制台甚至显示查询已成功执行,但它就是不起作用。
'use client'
import '@/styles/gameStyle.css'
import React, { useState, useEffect, useCallback } from "react"
import { api } from "@/trpc/react"
import { v4 as uuidv4 } from 'uuid'
import { useMotionValue, useDragControls, motion, AnimatePresence } from "framer-motion"
import Card from "../components/card/card"
import DialogInfoModal from "../components/game/dialogInfoModal"
import PlayButton from "../components/game/PlayButton"
import PlayerForm from "../components/game/PlayerForm"
import DeckChoose from "../components/game/DeckChoose"
import { Button } from "@/components/ui/button"
import { useToast } from "@/hooks/use-toast"
import { Loader2 } from "lucide-react"
export default function Game() {
const [selectedDeckIds, setSelectedDeckIds] = useState<string[]>([])
const [gameStage, setGameStage] = useState<'initial' | 'deckChoose' | 'playerForm' | 'gamePlay'>('initial')
const [currentMatchId, setCurrentMatchId] = useState<string | null>(null)
const [playersList, setPlayersList] = useState<{ id: string; name: string }[]>([])
const [currentPlayerIndex, setCurrentPlayerIndex] = useState(0)
const [exitX, setExitX] = useState(0)
const x = useMotionValue(0)
const dragControls = useDragControls()
const { toast } = useToast()
const { data: cardData, refetch, isLoading: isCardLoading, error: cardError } = api.card.getRandomCardByDeckId.useQuery(
{ deckIds: selectedDeckIds },
{
enabled: selectedDeckIds.length > 0 && gameStage === 'gamePlay',
retry: false,
onError: (error) => {
toast({ description: 'Error fetching card: ' + error.message, variant: "destructive" })
}
}
)
const { mutate: playerMutate } = api.players.create.useMutation()
const { mutate: matchesMutate, isLoading: isMatchMutating } = api.match.create.useMutation({
onSuccess: (matchData) => {
setCurrentMatchId(matchData.id)
console.log('Match created with ID:', matchData.id)
},
onError: (error) => {
toast({ description: 'Erro ao criar partida: ' + error.message, variant: "destructive" })
}
})
const { mutate: matchPlayersMutate } = api.matchPlayers.create.useMutation()
useEffect(() => {
if (gameStage === 'gamePlay' && selectedDeckIds.length > 0) {
refetch()
}
}, [gameStage, selectedDeckIds, refetch])
const handlePlayButtonClick = () => {
setGameStage('deckChoose')
createMatch()
}
const handlePlayerForm = () => {
setGameStage('gamePlay')
}
const createMatch = () => {
const date = new Date()
const status = 'Started'
matchesMutate({ status, date })
}
const handlePlayerSubmit = (name: string) => {
const id = uuidv4()
playerMutate({ id, name }, {
onSuccess: () => {
toast({ description: 'Jogador Adicionado com Sucesso!' })
setPlayersList((prev) => [...prev, { id, name }])
if (currentMatchId) {
matchPlayersMutate({
matchId: currentMatchId,
playerId: id,
})
}
}
})
}
const handleDeckSelection = useCallback((chosenDeckIds: string[]) => {
setSelectedDeckIds(chosenDeckIds)
setGameStage('playerForm')
}, [])
const handleDragEnd = (
_: MouseEvent | TouchEvent | PointerEvent,
info: { offset: { x: number } }
) => {
if (info.offset.x < -150 || info.offset.x > 150) {
setExitX(info.offset.x < -150 ? -400 : 400)
console.log(info.offset.x < -150 ? 'esquerda' : 'direita')
setCurrentPlayerIndex((prevIndex) => (prevIndex + 1) % playersList.length)
refetch()
}
}
return (
<main className="relative main flex h-screen flex-col items-center justify-center bg-gradient-to-b from-[#15042e] to-[#070012]">
<AnimatePresence mode="wait">
{gameStage === 'initial' && (
<motion.div
key="playButton"
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
transition={{ duration: 0.5 }}
>
<PlayButton onClick={handlePlayButtonClick} />
</motion.div>
)}
{gameStage === 'deckChoose' && (
<motion.div
key="deckChoose"
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
transition={{ duration: 0.5 }}
>
<DeckChoose onDeckSelection={handleDeckSelection} />
</motion.div>
)}
{gameStage === 'playerForm' && (
<motion.div
key="playerForm"
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
transition={{ duration: 0.5 }}
>
<PlayerForm setPlayerFormVisible={handlePlayerForm} onSubmit={handlePlayerSubmit} playersList={playersList} />
</motion.div>
)}
{gameStage === 'gamePlay' && (
<motion.div
key="gamePlay"
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0 }}
transition={{ duration: 0.5 }}
className="w-full h-full flex flex-col items-center justify-center"
>
<h2 className="text-white mb-4 absolute top-20 text-xl font-semibold">Turno de: {playersList[currentPlayerIndex]?.name}</h2>
<div className="flex justify-center items-center w-full h-full">
{isCardLoading ? (
<Loader2 className="h-8 w-8 animate-spin" />
) : cardError ? (
<div className="text-center">
<p className="text-red-500 mb-4">Error: {cardError.message}</p>
<Button onClick={() => refetch()}>Tente Novamente</Button>
</div>
) : cardData && cardData.length > 0 ? (
<AnimatePresence>
{cardData.map((data) => (
<Card
key={data.id ?? uuidv4()}
drag="x"
cardDescription={data.description ?? ''}
cardNumber={data.level ?? 0}
cardTheme={data.theme ?? ''}
cardName={data.name ?? ''}
cardSubtitle={data.subtitle ?? ''}
x={x}
dragControls={dragControls}
onDragEnd={handleDragEnd}
/>
))}
</AnimatePresence>
) : (
<p className="text-white">Sem Cartas Nesse Deck</p>
)}
</div>
</motion.div>
)}
</AnimatePresence>
<div className="absolute bottom-8 right-8">
<DialogInfoModal />
</div>
</main>
)
}
这就是游戏页面组件。
import { z } from "zod";
import { createTRPCRouter, publicProcedure } from "@/server/api/trpc";
import { cards } from "@/server/db/schema";
import { db } from "@/server/db/index"
import { sql, inArray } from "drizzle-orm";
export async function getRandomCardByDeckIds(deckIds: string[]) {
if (deckIds.length === 0) {
throw new Error("No deck IDs provided");
}
const query = sql`
SELECT * FROM "pinga-party_card"
WHERE ${inArray(cards.deckId, deckIds)}
ORDER BY random()
LIMIT 1
`;
return await db.execute(query);
}
export async function getRandomCard() {
return await db.execute(sql`SELECT * FROM "pinga-party_card" ORDER BY random() LIMIT 1`);
}
export const cardRouter = createTRPCRouter({
getRandomCardByDeckId: publicProcedure
.input(z.object({
deckIds: z.array(z.string())
}))
.query(async ({ input }) => {
return await getRandomCardByDeckIds(input.deckIds);
}),
getRandomCard: publicProcedure.query(async () => {
return await getRandomCard();
}),
get: publicProcedure.query(async () => {
return await db.query.cards.findMany({
with: {
deck: true,
},
});
}),
create: publicProcedure
.input(
z.object({
name: z.string(),
description: z.string(),
theme: z.string(),
level: z.number().int(),
deckId: z.string(),
subtitle: z.string(),
})
)
.mutation(async (opts) => {
const { input } = opts;
await db.insert(cards).values({
name: input.name,
description: input.description,
theme: input.theme,
level: input.level,
deckId: input.deckId,
subtitle: input.subtitle,
})
}),
})
这就是模型。
我已经检查了数据库,但问题似乎可能出在代码中的某个地方。
需要什么我就发给你。我已经尝试过日志、数据库、gpts(如 chatgpt、gemini、v0),但没有成功。
很高兴认识你。我已阅读您的问题并检查您的代码。 我希望我的解决方案可以帮助您。
当然!以下是您的 React.js 和 Next.js 应用程序可能获取数据但无法渲染数据的一些潜在原因,以及故障排除步骤:
状态管理问题:确保在获取数据后正确更新组件的状态。如果状态未正确更新,即使数据已成功获取,组件也不会重新渲染。
条件渲染逻辑:检查渲染数据的条件。确保您的渲染逻辑正确处理数据尚不可用或正在加载的场景。
处理异步获取:确保您的获取逻辑正确处理承诺,并且您可以很好地管理加载状态。正确的错误处理还可以提供对问题的洞察。
服务器端和静态属性:如果使用
getServerSideProps
或 getStaticProps
等 Next.js 功能,请验证这些函数是否将正确的数据返回到您的组件。
渲染列表:渲染数据列表时,确认每个项目都有唯一的键。这有助于 React 跟踪列表的更改并可能影响渲染。
上下文或状态管理工具问题:如果使用上下文或状态管理库,请确保组件正确订阅更新。
如果检查这些区域后问题仍然存在,请考虑隔离应用程序的某些部分以确定问题的根源。 如果你愿意,我可以在短时间内解决你的问题。