这是我的代码:
const Practice = () => {
const [todo, setTodo] =useState("");
const [todos,setTodos]=useState([])
const onSubmit =async(event) =>{
event.preventDefault();
setTodos((currnet)=>[todo, ...currnet])
setTodo("")
try {
const docRef = await addDoc(collection(db, "todos"), {
todos,
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
}
const onChange = (event)=>{
setTodo(event.target.value)
}
console.log(todos)
return (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={todo} type="text" placeholder="Write" />
<input type="submit" value="GO!!" />
</form>
</>
)
}
和我在标签中输入一些单词,但最后输入的单词不存在我的firebase数据库。为什么我的数据库不存在?为什么要创建新的空数组?输入图片描述
输入图片描述
你的问题与钩子的异步特性有关。
在onSubmit
函数中,您使用setTodos
钩子(即异步)设置todos
,然后读取todos
值(将其存储到firebase)。
你不能在异步上下文中写这段代码!事实上,可能是todos
将在hook设置他之前被读取(结果将是不是所有的数据将被存储到firebase)。
要解决这个bug,你必须这样使用useEffect
钩子:
const Practice = () => {
const [todo, setTodo] =useState("");
const [todos,setTodos]=useState([])
useEffect(() => {
// 1) define an async function in useEffect hook
const storeData = async () => {
try {
const docRef = await addDoc(collection(db, "todos"), {
todos,
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
}
// 2) reset todo
setTodo("");
// 3) store todos into firebase
storeData();
}, [todos]);
const onSubmit =async(event) =>{
event.preventDefault();
setTodos((currnet)=>[todo, ...currnet]);
}
const onChange = (event)=>{
setTodo(event.target.value)
}
return (
<>
<form onSubmit={onSubmit}>
<input onChange={onChange} value={todo} type="text" placeholder="Write" />
<input type="submit" value="GO!!" />
</form>
</>
)
}
解释:
onSubmit
功能只需要设置todos
(无需进一步操作);- 当
todos
改变时,useEffect
钩子将被调用(只有在这个时候你才100%确定todos
将包含所有你必须存储到firebase中的元素!); - 现在在
useEffect
中,你可以清理todo
,然后调用storeData
函数将todos
存储到firebase。
附加说明:为什么我在useEffect
中定义了一个async函数,如果我可以这样写:
useEffect(async () => { // never use async useEffect!!!
try {
const docRef = await addDoc(collection(db, "todos"), {
todos,
});
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
}, [todos])
你不能写异步useEffect
是有原因的,但我不是专家,所以我强烈建议你阅读这篇文章。