英文:
How to automatically update data after a change
问题
我正在制作一个用于写词的小应用,使用Firestore云进行数据存储。我使用 onSubmit
将数据发送到Firestore进行存储。
一切都运行正常,保存到云端,但页面上的数据没有更新,需要重新加载页面,之后数据才会更新。
我该如何解决这个问题,是需要每次渲染一个新数组并从服务器获取数据来更新数据 (fetchProduct
),还是有其他方法可以解决?
function Menu() {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const { user } = UserAuth();
const fetchProduct = async () => {
const ref = collection(db, "langcards-db");
const q = query(ref, where("author", "==", user.uid));
const querySnapshot = await getDocs(q);
const arr = [];
querySnapshot.forEach((doc) => {
arr.push({
...doc.data(),
id: doc.id,
});
});
setData(arr);
setIsLoading(false);
};
useEffect(() => {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, []);
useEffect(() => {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, [user]);
const onSubmit = async (e) => {
e.preventDefault();
let rw = word.replace(/\s/g, "");
let rt = translate.replace(/\s/g, "");
if (rw.length >= 1 && rt.length >= 1) {
setWarn(false);
await addDoc(collection(db, "langcards-db"), {
word: word,
translate: translate,
note: note,
category: "category",
author: user.uid,
});
setWord("");
setTranslate("");
setNote("");
console.log(data)
} else {
setWarn(true);
}
};
return (
<div className="main-inner">
{isLoading ? (
<Loader />
) : (
<div className="content">
<Routes>
<Route
path="addcard"
element={
<AddCard
onChangeWord={onChangeWord}
onChangeNote={onChangeNote}
onChangeTranslate={onChangeTranslate}
onSubmit={onSubmit}
word={word}
translate={translate}
note={note}
warn={warn}
resetFormAdd={resetFormAdd}
/>
}
/>
<Route
path="saved"
element={<Saved data={data} setData={setData} />}
/>
</Route>
</Routes>
</div>
);
}
export default Menu;
英文:
I am making a small application for writing words, using a Firestore Cloud for data storage. I use onSubmit
to send data to Firestore for storage.
Everything works and is saved to the cloud, but the data is not updated on the page, for which you need to reload the page and after that the data will already be updated.
How can I solve this problem, do I need to render a new array every time and get data from the server in order to update the data (fetchProduct
), or is it possible in some other way?
function Menu() {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const { user } = UserAuth();
const fetchProduct = async () => {
const ref = collection(db, "langcards-db");
const q = query(ref, where("author", "==", user.uid));
const querySnapshot = await getDocs(q);
const arr = [];
querySnapshot.forEach((doc) => {
arr.push({
...doc.data(),
id: doc.id,
});
});
setData(arr);
setIsLoading(false);
};
useEffect(() => {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, []);
useEffect(() => {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, [user]);
const onSubmit = async (e) => {
e.preventDefault();
let rw = word.replace(/\s/g, "");
let rt = translate.replace(/\s/g, "");
if (rw.length >= 1 && rt.length >= 1) {
setWarn(false);
await addDoc(collection(db, "langcards-db"), {
word: word,
translate: translate,
note: note,
category: "category",
author: user.uid,
});
setWord("");
setTranslate("");
setNote("");
console.log(data)
} else {
setWarn(true);
}
};
return (
<div className="main-inner">
{isLoading ? (
<Loader />
) : (
<div className="content">
<Routes>
<Route
path="addcard"
element={
<AddCard
onChangeWord={onChangeWord}
onChangeNote={onChangeNote}
onChangeTranslate={onChangeTranslate}
onSubmit={onSubmit}
word={word}
translate={translate}
note={note}
warn={warn}
resetFormAdd={resetFormAdd}
/>
}
/>
<Route
path="saved"
element={<Saved data={data} setData={setData} />}
/>
</Route>
</Routes>
</div>
);
}
export default Menu;
答案1
得分: 1
对于这个问题,你不应该使用getDocs
,而是应该使用onSnapshot
来监听数据的更改。这样你可以直接更新状态,而不必每次都创建一个新数组。然后在访问数据状态中的条目时,你可以直接引用.data
。
useEffect(() => {
const ref = collection(db, "langcards-db");
const q = query(ref, where("author", "==", user.uid));
const unsubscribe = onSnapshot(q, { includeMetadataChanges: true }, (querySnapshot) => {
setData([]); // 清空状态
querySnapshot.forEach((doc) => {
// 对数据进行操作(像以前一样将其附加到数据数组中)
setData(old => [...old, {"id" : doc.id, "data" : doc.data()});
});
});
return () => { unsubscribe(); };
}, [])
在这个文档中,你可以了解更多关于如何从Firestore获取数据的信息。
英文:
For this problem you should not use getDocs
but onSnapshot
which listens for changes in the data. Also, this way you can update the state directly and don`t have to create a new array each time. Then you can directly refer to .data
when accessing an entry from the data state.
useEffect(() => {
const ref = collection(db, "langcards-db");
const q = query(ref, where("author", "==", user.uid));
const unsubscribe = onSnapshot(q, { includeMetadataChanges: true }, (querySnapshot) => {
setData([]); // Empty state
querySnapshot.forEach((doc) => {
// Do something with your data (append it to the data array like before)
setData(old => {...old, {"id" : doc.id, "data" : doc.data()});
});
});
return () => { unsubscribe(); };
}, [])
In this doc you can read more about how to fetch data from your firestore.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论