React.js中调用readContacts()无法在网页输出内容是什么原因?
问题原因
- 你的
readContacts函数本身没有返回值:回调函数内的return snapshot.val()仅将值返回给Firebase的on事件回调方法,而非readContacts的调用方,直接调用readContacts()拿到的是undefined,自然无法渲染。 - Firebase数据库读取是异步操作,就算你做了返回值处理,也无法在同步渲染逻辑里直接拿到异步返回的结果。
- 你没有把联系人数据存入React响应式状态,就算拿到了数据也无法触发组件重新渲染更新页面。
修正方案
1. 修改ContactsContext.js
import React, { useContext, useState } from "react" import { db } from "../firebase" import { useAuth } from "./AuthContext" const ContactsContext = React.createContext() export function useContacts() { return useContext(ContactsContext) } export function ContactsProvider({ children }) { const { currentUser } = useAuth() // 新增响应式状态存储联系人数据 const [contacts, setContacts] = useState([]) function createContact(email, firstName, lastName) { db.ref("users/" + currentUser.uid + "/contacts/" + firstName + " " + lastName).set({ Email: email, FirstName: firstName, LastName: lastName }) } function readContacts() { // 存储监听器引用,后续可以解绑避免内存泄漏 const contactRef = db.ref("users/" + currentUser.uid + "/contacts/") contactRef.on("value", (snapshot) => { const data = snapshot.val() // 将Firebase返回的对象转为数组方便渲染 const contactList = data ? Object.values(data) : [] setContacts(contactList) }) // 返回解绑函数 return () => contactRef.off("value") } const value = { createContact, readContacts, // 把联系人状态加入context contacts } return ( <ContactsContext.Provider value={value}> {children} </ContactsContext.Provider> ) }
2. 修改Contacts.js
import React, { useEffect } from "react" import { ListGroup } from "react-bootstrap" import { useContacts } from "../contexts/ContactsContext" export default function Contacts() { const { readContacts, contacts } = useContacts() // 组件挂载时初始化数据监听,卸载时解绑监听器 useEffect(() => { const unSubscribe = readContacts() return () => unSubscribe() }, [readContacts]) return ( <ListGroup variant="flush"> {/* 遍历渲染联系人列表 */} {contacts.map((contact, index) => ( <ListGroup.Item key={index}> {contact.FirstName} {contact.LastName} - {contact.Email} </ListGroup.Item> ))} </ListGroup> ) }
补充说明
- 当前你用
firstName + lastName作为数据库节点key存在重名覆盖的风险,建议改用Firebase的push()方法生成唯一ID作为key,或者用邮箱地址这类唯一标识。 - 如果你不需要实时监听联系人数据更新,可以把
on("value")改为once("value"),读取一次后就自动结束请求,不需要手动解绑。
内容的提问来源于stack exchange,提问作者NoobDev
相关产品推荐
相关产品推荐

