React中子组件调用completeCard时如何向父组件传值更新completedChallenges状态
实现方案
核心思路是父组件向子组件传递回调函数,子组件完成任务逻辑后调用该回调,把完成的卡片ID回传给父组件更新状态。
步骤1:修改父组件Dashboard
- 新增处理挑战完成的回调函数,接收cardID参数更新
completedChallenges状态,同时刷新展示的卡片列表 - 渲染Card组件时将回调函数作为prop传递给子组件
- 优化原有异步逻辑的潜在问题:
setUID是异步操作,调用setPage时直接取auth.currentUser.uid避免拿到旧值
修改后的父组件完整代码:
import React, { useState, useEffect } from 'react'; import { auth, database } from '../../utils/firebase'; import { ref, get} from "firebase/database"; import { Redirect } from 'react-router-dom'; import { onAuthStateChanged } from "firebase/auth"; //Components import Navbar from './Navbar'; import ProgressBar from './ProgressBar'; import Card from './Card'; function Dashboard() { const [uid, setUID] = useState(""); const [completedChallenges, setCompletedChallenges] = useState([]); const [displayCards, setDisplayCard] = useState([]); // 新增:处理挑战完成的回调函数 const handleChallengeComplete = (finishedCardID) => { // 不可变方式更新已完成挑战列表 setCompletedChallenges(prev => [...prev, finishedCardID]); // 刷新卡片展示,过滤掉已完成的卡片 setCards(); } function setCards() { const userRef = ref(database, 'challenges'); get(userRef).then((snapshot) => { const data = snapshot.val(); var currentDisplayCards = []; for(let i =1; i <= 10; i++){ if(currentDisplayCards.length == 5) {break;} if(completedChallenges.indexOf(parseInt(i)) == -1){ currentDisplayCards.push(data[i]); } } setDisplayCard(currentDisplayCards); }); } function setPage() { const currentUid = auth.currentUser.uid; setUID(currentUid); const userRef = ref(database, 'users/' + currentUid); get(userRef).then((snapshot) => { const data = snapshot.val(); setCompletedChallenges(data["challenges"]); setCards(); }); } useEffect(() => { onAuthStateChanged(auth, (user) => { if (user) { setPage(); } else { return <Redirect to= '/'/> } }); }, []); // 移除uid依赖,onAuthStateChanged只会在auth状态变化时触发 return ( <div> <Navbar/> <h2> Your missions </h2> {displayCards.map((card) => ( <Card uid={uid} key={card.key} cardID={card.key} name={card.name} description={card.description} // 传递回调给子组件 onComplete={handleChallengeComplete} /> ))} </div> ); } export default Dashboard;
步骤2:修改子组件Card
- 移除冗余的uid本地状态,直接使用props传递的uid即可
- 在
completeCard的firebase更新操作成功后,调用父组件传递的onComplete回调,把当前卡片ID回传 - 补充update操作的错误捕获,避免异常无提示
修改后的子组件完整代码:
import React from 'react'; import { ref, update, get} from "firebase/database"; import { database } from '../../utils/firebase'; import './Card.css'; function Card(props) { function completeCard() { const userRef = ref(database, 'users/' + props.uid); get(userRef).then((snapshot) => { const data = snapshot.val(); const completedMissions = data["challenges"]; completedMissions.push(props.cardID); const updates = {}; updates['/users/' + props.uid +'/challenges'] = completedMissions; // firebase更新成功后调用父组件回调 update(ref(database), updates).then(() => { props.onComplete(props.cardID); }).catch(err => { console.error("更新挑战状态失败:", err); }); }); } return( <div className="card"> <h1>{props.name}</h1> <p>{props.description}</p> <button onClick={completeCard}>Completar</button> <button>+Info</button> </div> ) } export default Card;
内容的提问来源于stack exchange,提问作者Lara Calvo
相关产品推荐
相关产品推荐

