FireStore - 使用新数据更新 UI,无需重新加载浏览器

IT技术 reactjs google-cloud-firestore react-hooks
2021-05-07 23:04:23

我使用以下组件在 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 集合中,但我在页面上看不到任何变化。我仍然必须刷新(重新加载)浏览器才能看到这些更改。我究竟做错了什么?

2个回答

我会以不同的方式接近它 - 为什么上传然后再次加载?

当 onAdd 被调用时,将您的数据保存到设置状态,状态的变化将使用新数据重新渲染您的组件。

如果您坚持使用 save\load 路径,请尝试将 use effect hook 与此处提到的 set state 结合使用:https : //dev.to/chantastic/connect-useeffect-and-usestate-to-update-components-with -data-4aaj

React.js 的很多功能都在状态中,使用它:)

没有人会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");
    }
  });
});

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

另见: