React+Firebase实现带导航的文档按钮数组问题排查
问题:Firebase Firestore数据渲染按钮数组失败的错误分析与修复
需求说明
- 从Cloud Firestore的
Curso集合中获取所有文档 - 将文档数据转化为按钮数组渲染到页面
- 每个按钮点击时携带对应文档的完整信息,导航至
/LimpiarCurso页面供后续使用
此前可行的实现(JSON数据+map)
{aulas.map((aula) => ( <div key={aula.id} className="col-md-4" style={{paddingBottom: '10px', paddingTop: '5px'}}> <Button className={(aula.estado==='sucio'? 'btn btn-danger': 'btn btn-success')} onClick={()=> navigate('/LimpiarCurso', {state: {id:aula.id,num_aula:aula.num_aula,año:aula.año, division:aula.division,horario_retiro:aula.horario_retiro}})}> {aula.año}{aula.division} </Button> </div> ))}
当前Firebase版本的错误代码
export default function AdministrarCurso(){ const navigate= useNavigate(); function mostrarCursos(navigate){ const querySnapshot = getDocs(collection(db, "Curso")); querySnapshot.forEach((doc) => { // console.log(doc); // console.log(doc.data()); console.log(doc.get('anio')+doc.get('division')); <div className="col-md-4" style={{paddingBottom: '10px', paddingTop: '5px'}}> <Button className={(doc.get('estado')==='sucio'? 'btn btn-danger': 'btn btn-success')} onPress={()=> navigate('/LimpiarCurso', {state: doc.data()})}> {doc.get('anio')+doc.get('division')} </Button> </div> }); } return( <Container> <AppBar style={{background: 'transparent', boxShadow: 'none'}}> <Toolbar> <Button onClick={()=> LogOut(navigate)}>Cerrar Sesión</Button> </Toolbar> </AppBar> <div className="row"> {mostrarCursos()} {/* Acá hay botones que se generan en base a la cantidad de documentos que tenga el forEach // Que te redireccionan a la pantalla de Limpiar Curso // */} </div> </Container> ) }
遇到的错误
- 初始错误:
Objects are not valid as a react child - 调整后错误:
querySnapshot 不是函数
错误原因与修复方案
1. 异步函数处理错误
getDocs是异步函数,直接赋值会得到Promise对象而非查询快照,导致forEach调用失败。必须用async/await配合useEffect在组件挂载时异步获取数据。
2. 未正确返回JSX元素
mostrarCursos函数没有收集并返回生成的JSX元素,React无法渲染undefined或Promise对象,引发“无效React子元素”错误。需要用状态存储文档数据,再通过map遍历生成按钮。
3. 事件名错误
Web React中按钮点击事件应为onClick,而非React Native的onPress,否则点击逻辑不会触发。
修正后的完整代码
import { useState, useEffect } from 'react'; import { getDocs, collection } from 'firebase/firestore'; import { useNavigate } from 'react-router-dom'; import { Container, AppBar, Toolbar, Button } from '@mui/material'; // 按实际使用的组件库调整 export default function AdministrarCurso(){ const navigate = useNavigate(); const [cursos, setCursos] = useState([]); // 组件挂载时异步获取Firestore数据 useEffect(() => { const fetchCursos = async () => { const querySnapshot = await getDocs(collection(db, "Curso")); // 将文档数据转换为包含id的数组 const cursosData = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setCursos(cursosData); }; fetchCursos(); }, []); return( <Container> <AppBar style={{background: 'transparent', boxShadow: 'none'}}> <Toolbar> <Button onClick={()=> LogOut(navigate)}>Cerrar Sesión</Button> </Toolbar> </AppBar> <div className="row"> {cursos.map((curso) => ( <div key={curso.id} className="col-md-4" style={{paddingBottom: '10px', paddingTop: '5px'}}> <Button className={curso.estado === 'sucio' ? 'btn btn-danger' : 'btn btn-success'} onClick={() => navigate('/LimpiarCurso', { state: curso })} > {curso.anio}{curso.division} </Button> </div> ))} </div> </Container> ) }
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

