自动在更改后更新数据的方法

huangapple go评论57阅读模式
英文:

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 () =&gt; {
const ref = collection(db, &quot;langcards-db&quot;);
const q = query(ref, where(&quot;author&quot;, &quot;==&quot;, user.uid));
const querySnapshot = await getDocs(q);
const arr = [];
querySnapshot.forEach((doc) =&gt; {
arr.push({
...doc.data(),
id: doc.id,
});
});
setData(arr);
setIsLoading(false);
};
useEffect(() =&gt; {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, []);
useEffect(() =&gt; {
if (user) {
fetchProduct();
} else {
setData([]);
setIsLoading(false);
}
}, [user]);
const onSubmit = async (e) =&gt; {
e.preventDefault();
let rw = word.replace(/\s/g, &quot;&quot;);
let rt = translate.replace(/\s/g, &quot;&quot;);
if (rw.length &gt;= 1 &amp;&amp; rt.length &gt;= 1) {
setWarn(false);
await addDoc(collection(db, &quot;langcards-db&quot;), {
word: word,
translate: translate,
note: note,
category: &quot;category&quot;,
author: user.uid,
});
setWord(&quot;&quot;);
setTranslate(&quot;&quot;);
setNote(&quot;&quot;);
console.log(data)
} else {
setWarn(true);
}
};
return (
&lt;div className=&quot;main-inner&quot;&gt;
{isLoading ? (
&lt;Loader /&gt;
) : (
&lt;div className=&quot;content&quot;&gt;
&lt;Routes&gt;
&lt;Route
path=&quot;addcard&quot;
element={
&lt;AddCard
onChangeWord={onChangeWord}
onChangeNote={onChangeNote}
onChangeTranslate={onChangeTranslate}
onSubmit={onSubmit}
word={word}
translate={translate}
note={note}
warn={warn}
resetFormAdd={resetFormAdd}
/&gt;
}
/&gt;
&lt;Route
path=&quot;saved&quot;
element={&lt;Saved data={data} setData={setData} /&gt;}
/&gt;
&lt;/Route&gt;
&lt;/Routes&gt;
&lt;/div&gt;
);
}
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(() =&gt; {
const ref = collection(db, &quot;langcards-db&quot;);
const q = query(ref, where(&quot;author&quot;, &quot;==&quot;, user.uid));
const unsubscribe = onSnapshot(q, { includeMetadataChanges: true }, (querySnapshot) =&gt; {
setData([]); // Empty state
querySnapshot.forEach((doc) =&gt; {
// Do something with your data (append it to the data array like before)
setData(old =&gt; {...old, {&quot;id&quot; : doc.id, &quot;data&quot; : doc.data()});
});
});
return () =&gt; { unsubscribe(); };
}, [])

In this doc you can read more about how to fetch data from your firestore.

huangapple
  • 本文由 发表于 2023年2月6日 21:14:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/75361784.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定