【问题标题】:How to make useEffect rerender after the data is changed?数据更改后如何使useEffect重新渲染?
【发布时间】:2021-12-10 01:58:02
【问题描述】:

我希望 useEffect 获取和呈现 rooms 数据。并在将新房间添加到rooms时重新渲染数据

获取数据并使用 useEffect 和空依赖项显示数据的代码。

const [rooms, setRooms] = useState([]);

  const getRoomsData = async () => {
    const querySnapshot = await getDocs(collection(db, "rooms"));
    const data = querySnapshot.docs.map((doc) => ({
      id: doc.id,
      data: doc.data(),
    }));

    setRooms(data);
  };

  useEffect(() => {
    getRoomsData();
    console.log("rerendered");
  }, []);

使用此代码,在我向rooms 添加新房间后。我需要手动刷新页面以查看呈现的新数据。将新的“房间”添加到rooms 后,我应该怎么做才能使其重新呈现?

添加房间的代码:

    const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      });
    }
  };

我尝试将房间添加到 useEffect 依赖项,它具有我想要的结果(无需刷新),但这只是因为它无限渲染,这很糟糕。正确的做法是什么?

【问题讨论】:

  • 您如何知道 data 何时更改以将状态更新加入队列?你在使用火力基地吗?难道没有onSnapshot 方法可以用于集合吗?
  • 是的,我正在使用 firebase。所以基本上我希望我的应用程序在我将文档添加到我的 firebase 集合“房间”后重新呈现。我希望我的应用程序获取数据并重新呈现它,因此我不必刷新页面即可查看更新的数据。我该怎么做?
  • 我明白了,所以您知道数据何时发生更改,因为您刚刚添加了它。如果您在“添加房间”代码的末尾调用 getRoomsData 以重新获取数据会发生什么?

标签: javascript reactjs use-effect use-state


【解决方案1】:

因为useEffect 中的函数正在更新效果的依赖数组中rooms 的状态,所以您将获得无限的重新渲染。这总是会导致无限的重新渲染。

逐字回答您的问题: “如何让它仅在数据更改时重新呈现?”

由于roomsdata 设置为相同,您可以保持useEffect 不变,然后创建另一个useEffect 以仅在组件安装调用getRoomsData() 时触发。

const [rooms, setRooms] = useState([]);

  const getRoomsData = async () => {
    const querySnapshot = await getDocs(collection(db, "rooms"));
    const data = querySnapshot.docs.map((doc) => ({
      id: doc.id,
      data: doc.data(),
    }));

    setRooms(data);
  };

  useEffect(() = > {
    getRoomsData();
  }, [])

  useEffect(() => {
    console.log("rerendered");
  }, [rooms]);

我认为解决您的问题的真正关键是知道何时调用getRoomsData(),因为根据这一点,您将更改useEffect 依赖数组以满足该需求。

【讨论】:

  • 感谢您的回答,但我仍然很困惑。每当我在收藏中的“房间”文档中添加一些数据时,如何运行getRoomsData?我正在显示房间数据,用户可以添加更多房间。为了显示在屏幕上添加的新房间,我必须刷新我不喜欢的页面。将新的“房间”添加到“房间”而不刷新时如何重新渲染和显示数据?
  • 这将完全取决于其余的代码。如果你编辑你的问题以包含更多代码,我可以给你一个明确的答案。您如何将rooms 添加到数据库中?我不知道你用的是哪个数据库。
  • 抱歉,我之前可能没有正确解释我的问题,我已经编辑了问题。谢谢你。顺便说一句,我正在使用 firebase。
【解决方案2】:

我可以想到两种方法来解决这个问题,而不必使用useEffect,第一种是一种解决方法,您可以在本地更新rooms 状态而无需从服务器获取它,即,您是基本上是在 rooms 的现有数组中构造和附加一个对象,这只有在你知道对象的结构时才有可能,看看你的 getRoomsData 函数,似乎你正在返回一个数据数组,每个项目都有遵循对象结构。

{
 id: <DOCUMENT_ID>,
 data: {
  name: <ROOM_NAME>
 }
}

所以,当你添加一个房间时,你可以这样做:

   const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      });
      let newRoom = {
        id: Math.random(), //random id
        data: {
          name: roomName
        }
      }
      setRooms([...rooms,newRoom])
  };

这样,您还可以减少网络调用的数量,这是一个性能奖励,但唯一的缺点是您必须确定对象结构,以便相应地绘制结果。
如果您不确定对象结构,您可以在将新房间添加到集合后调用getRoomsData,如下所示:

   const roomName = prompt("please enter name for chat room");

    if (roomName) {
      addDoc(collection(db, "rooms"), {
        name: roomName,
      }).then(res=>{
          getRoomsData();
      })
  };

这将确保获取最新数据(包括最近添加的房间)并使用所有结果呈现您的组件。 在您遵循的任何一种方法中,当组件使用空依赖数组安装时,您只能使用一次 useEffect

 useEffect(() => {
    getRoomsData();
    //console.log("rerendered");
  }, []);

通过这样做,您首先基本上在用户第一次访问此页面时/第一次安装组件时显示数据。在后续添加中,您可以在将新添加的room 添加到数据库后将其作为对象附加到rooms 数组中,或者将其添加到数据库并再次获取所有结果,以便最新添加的内容呈现在屏幕。

【讨论】:

    【解决方案3】:

    当使用 useEffect 获取数据时,它期望进行同步调用。从 Firestore 请求数据是异步的,所以为了解决这个问题,我们可以添加一个函数来包装 firestore 调用,称为 getRoomsData,如下所示:

    const [rooms, setRooms] = useState([]);
    
    
    
      useEffect(() = > {
        const getRoomsData = async () => {
        const querySnapshot = await getDocs(collection(db, "rooms"));
        const data = querySnapshot.docs.map((doc) => ({
          id: doc.id,
          data: doc.data(),
        }));
     setRooms(data);
     
      };
        getRoomsData();
      }, [])

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-30
      • 2021-04-24
      • 1970-01-01
      • 2022-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多