首页 > 解决方案 > FireStore - 使用新数据更新 UI 而无需重新加载浏览器

问题描述

我使用以下组件在 Google Cloud FireStore 集合中添加新数据:

import React, { useState } from 'react';
import { db } from '../firebase';

const AddCard = ({ totalDoclNumbers }) => {
  const [newOriginalText, setNewOriginalText] = useState([]);
  const [newTranslatedText, setNewTranslatedText] = useState([]);
  const nextNumber = totalDoclNumbers + 1;

  const onAdd = async () => {
    await db.collection('FlashCards').add({
      originalText: newOriginalText,
      translatedText: newTranslatedText,
      customId: Number(nextNumber),
    });
  };

  return (
    <ul>
      <li key={nextNumber}>
        <input
          type='text'
          readOnly
          defaultValue={nextNumber}
        />
        <div>
            <textarea
              placeholder='English'
              onChange={(e) => setNewOriginalText(e.target.value)}
            />
        </div>
        <textarea
          placeholder='Translation'
          onChange={(e) => setNewTranslatedText(e.target.value)}
        />
        <button onClick={onAdd}>
          Add
        </button>
      </li>
    </ul>
  );
};

导出默认 AddCard;

添加按钮有效,我可以看到新数据已添加到 Google 服务器上的集合中,但是为了能够查看这些新数据,我必须刷新页面。

为了修复它,我决定使用onSnapshot函数,如下所示:

import React, { useState } from 'react';
import { db } from '../firebase';

const AddCard = ({ totalDoclNumbers }) => {
  const [newOriginalText, setNewOriginalText] = useState([]);
  const [newTranslatedText, setNewTranslatedText] = useState([]);
  const nextNumber = totalDoclNumbers + 1;

  const onAdd = async () => {
    await db.collection('FlashCards').add({
      originalText: newOriginalText,
      translatedText: newTranslatedText,
      customId: Number(nextNumber),
    });
  };

  const renderDocList = () => {
    return (
      <ul>
        <li key={nextNumber}>
          <input
            type='text'
            defaultValue={nextNumber}
          />
          <div>
              <textarea
                placeholder='English'
                onChange={(e) => setNewOriginalText(e.target.value)}
              />
          </div>
          <textarea
            placeholder='Translation'
            onChange={(e) => setNewTranslatedText(e.target.value)}
          />
          <button onClick={onAdd}>
            Add
          </button>
        </li>
      </ul>
    );
  };

  db.collection('FlashCards').onSnapshot((snapshot) => {
    let changes = snapshot.docChanges();
    changes.forEach((change) => {
      if (change.type === 'added') {
        renderDocList();
      }
    });
  });

  return <>{renderDocList()}</>;
};

export default AddCard;

但是,尽管新数据已添加到 FireStore 集合中,但我在页面上看不到任何更改。我仍然必须刷新(重新加载)浏览器才能看到这些更改。我究竟做错了什么?

标签: reactjsgoogle-cloud-firestorereact-hooks

解决方案


renderDocList没有人会在这个片段中看到调用的结果:

db.collection('FlashCards').onSnapshot((snapshot) => {
  let changes = snapshot.docChanges();
  changes.forEach((change) => {
    if (change.type === 'added') {
      renderDocList();
    }
  });
});

如果你想更新 UI,你需要告诉 React 有新数据要渲染。这就是useState钩子的用途。它不能完全了解您的代码如何影响正在呈现的内容,但您需要调用一个 setter 来修改组件呈现的状态。

所以说你的原始文本来自数据库,你会这样做:

db.collection('FlashCards').onSnapshot((snapshot) => {
  let changes = snapshot.docChanges();
  changes.forEach((change) => {
    if (change.type === 'added') {
      setNewOriginalText("new document added");
    }
  });
});

反过来,这将重新渲染任何显示原始文本的组件。

另见:


推荐阅读