如何 return 从 Firebase 到 React 组件的值?
How to return a value from Firebase to a react component?
我正在尝试从 Firebase 上的 RealtimeDatabase 读取一个值并将其呈现在一个元素中,但它保持 returning 未定义。我有以下代码:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
return snapshot.val().name;
})
}
const StudentName = (studentId) => ( <p>{getStudentName(studentId)}</p> )
我知道数据库本身或我找到的值都没有问题,因为如果我这样做:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
console.log(snapshot.val().name);
return "Test";
})
}
我仍然看到我的数据库中的正确名称按预期输出到控制台,但“测试”未 return 编辑到元素。但是,如果我这样做:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
console.log(snapshot.val().name);
})
return "Test";
}
然后“Test”被return编辑到
元素并显示。我很困惑,因为我不明白我的 console.log() 是如何在函数内部到达的,但是紧随其后的 'return' 语句不会 return.
React 和 Firebase 新手,请帮忙!谢谢。
编辑:我确定它是不言自明的,但您可以假设一个简单的数据库,其形式为:
{ "students": [
"0": { "name": "David" },
"1": { "name": "Sally" } ]}
如果'studentId'为0则'console.log(snapshot.val().name)'成功输出'David',但'David'不会return到
元素。
你不能 return 这样的异步调用。如果你检查调试器或添加一些日志记录,你会看到你的外部 return "Test"
在 console.log(snapshot.val().name)
被调用之前运行。
在 React 中,您需要使用 useState
钩子(或 setState
方法)来告知 React 新值,以便它可以重新渲染 UI .
我建议阅读 using the state hook, and the documentation on setState
上的 React 文档。
我不确定您在哪里使用 getStudentName
,但是您当前的代码使 real-time 监听器附加到该数据库位置。每次该位置的数据更新时,都会调用您的回调函数。因此,从这样的函数返回一个值没有多大意义。
如果您只想从数据库中获取名称一次,则可以使用 once()
方法,其中 returns 一个 Promise
包含您要查找的值。
作为另一个小优化,如果您只需要学生的姓名,请考虑取回 /students/{studentId}/name
。
const getStudentName = (studentId) => {
return firebase.database()
.ref("students")
.child(studentId)
.child("name")
.once("value")
.then(nameSnapshot => nameSnapshot.val());
}
使用上面的代码,getStudentName(studentId)
现在 returns 一个 Promise<string | null>
,其中 null
将在该学生不存在时返回。
getStudentName(studentId)
.then(studentName => { /* ... do something ... */ })
.catch(err => { /* ... handle errors ... */ })
如果您正在填充 <Student>
组件,继续使用 on
快照侦听器可能是更好的选择:
const Student = (props) => {
const [studentInfo, setStudentInfo] = useState({ status: "loading", data: null, error: null });
useEffect(() => {
// build reference
const studentDataRef = firebase.database()
.ref("students")
.child(props.studentId)
.child("name");
// attach listener
const listener = studentDataRef.on(
'value',
(snapshot) => {
setStudentInfo({
status: "ready",
data: snapshot.val(),
error: null
});
},
(error) => {
setStudentInfo({
status: "error",
data: null,
error
});
}
);
// detach listener in unsubscribe callback
return () => studentDataRef.off(listener);
}, [props.studentId]); // <- run above code whenever props.studentId changes
// handle the different states while the data is loading
switch (studentInfo.status) {
case "loading":
return null; // hides component, could also show a placeholder/spinner
case "error":
return (
<div class="error">
Failed to retrieve data: {studentInfo.error.message}
</div>
);
}
// render data using studentInfo.data
return (
<div id={"student-" + props.studentId}>
<img src={studentInfo.data.image} />
<span>{studentInfo.data.name}</span>
</div>
);
}
由于您最终可能会经常使用上述 useState
/useEffect
组合,您可以将其重写到您自己的 useDatabaseData
钩子中。
我正在尝试从 Firebase 上的 RealtimeDatabase 读取一个值并将其呈现在一个元素中,但它保持 returning 未定义。我有以下代码:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
return snapshot.val().name;
})
}
const StudentName = (studentId) => ( <p>{getStudentName(studentId)}</p> )
我知道数据库本身或我找到的值都没有问题,因为如果我这样做:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
console.log(snapshot.val().name);
return "Test";
})
}
我仍然看到我的数据库中的正确名称按预期输出到控制台,但“测试”未 return 编辑到元素。但是,如果我这样做:
const getStudentName = (studentId) => {
firebase.database().ref('students').child(studentId).on("value", (snapshot) => {
console.log(snapshot.val().name);
})
return "Test";
}
然后“Test”被return编辑到
元素并显示。我很困惑,因为我不明白我的 console.log() 是如何在函数内部到达的,但是紧随其后的 'return' 语句不会 return.
React 和 Firebase 新手,请帮忙!谢谢。
编辑:我确定它是不言自明的,但您可以假设一个简单的数据库,其形式为:
{ "students": [
"0": { "name": "David" },
"1": { "name": "Sally" } ]}
如果'studentId'为0则'console.log(snapshot.val().name)'成功输出'David',但'David'不会return到
元素。
你不能 return 这样的异步调用。如果你检查调试器或添加一些日志记录,你会看到你的外部 return "Test"
在 console.log(snapshot.val().name)
被调用之前运行。
在 React 中,您需要使用 useState
钩子(或 setState
方法)来告知 React 新值,以便它可以重新渲染 UI .
我建议阅读 using the state hook, and the documentation on setState
上的 React 文档。
我不确定您在哪里使用 getStudentName
,但是您当前的代码使 real-time 监听器附加到该数据库位置。每次该位置的数据更新时,都会调用您的回调函数。因此,从这样的函数返回一个值没有多大意义。
如果您只想从数据库中获取名称一次,则可以使用 once()
方法,其中 returns 一个 Promise
包含您要查找的值。
作为另一个小优化,如果您只需要学生的姓名,请考虑取回 /students/{studentId}/name
。
const getStudentName = (studentId) => {
return firebase.database()
.ref("students")
.child(studentId)
.child("name")
.once("value")
.then(nameSnapshot => nameSnapshot.val());
}
使用上面的代码,getStudentName(studentId)
现在 returns 一个 Promise<string | null>
,其中 null
将在该学生不存在时返回。
getStudentName(studentId)
.then(studentName => { /* ... do something ... */ })
.catch(err => { /* ... handle errors ... */ })
如果您正在填充 <Student>
组件,继续使用 on
快照侦听器可能是更好的选择:
const Student = (props) => {
const [studentInfo, setStudentInfo] = useState({ status: "loading", data: null, error: null });
useEffect(() => {
// build reference
const studentDataRef = firebase.database()
.ref("students")
.child(props.studentId)
.child("name");
// attach listener
const listener = studentDataRef.on(
'value',
(snapshot) => {
setStudentInfo({
status: "ready",
data: snapshot.val(),
error: null
});
},
(error) => {
setStudentInfo({
status: "error",
data: null,
error
});
}
);
// detach listener in unsubscribe callback
return () => studentDataRef.off(listener);
}, [props.studentId]); // <- run above code whenever props.studentId changes
// handle the different states while the data is loading
switch (studentInfo.status) {
case "loading":
return null; // hides component, could also show a placeholder/spinner
case "error":
return (
<div class="error">
Failed to retrieve data: {studentInfo.error.message}
</div>
);
}
// render data using studentInfo.data
return (
<div id={"student-" + props.studentId}>
<img src={studentInfo.data.image} />
<span>{studentInfo.data.name}</span>
</div>
);
}
由于您最终可能会经常使用上述 useState
/useEffect
组合,您可以将其重写到您自己的 useDatabaseData
钩子中。