UseState 不触发重新渲染

时间:2021-03-03 10:46:41

标签: javascript reactjs react-hooks state

我的订单列表有一个状态。在第一次更新时一切正常,但是当对数据库中的订单进行更新时,我的订单列表会更新但即使使用 <...>

也不会触发重新渲染

const [orders, setOrders] = useState([]);

  useEffect(() => {
    const unsubscribe = firebase.firestore()
      .collection("Orders")
      .orderBy("date", "desc")
      .limit(parseInt(limit, 10))
      .onSnapshot((snapshot) => {
        let oldOrders = orders;
        let addedOrders = []

        snapshot.docChanges().forEach((change) => {
          if (change.type === "added") {
            addedOrders.push({ ...change.doc.data(), id: change.doc.id })
          }
          if (change.type === "modified") {
            oldOrders[oldOrders.findIndex(x => x.id === change.doc.id)] = { ...change.doc.data(), id: change.doc.id }
          }
          if (change.type === "removed") {
            oldOrders.splice(oldOrders.findIndex(x => x.id === change.doc.id))
          }
        });
        if (addedOrders.length > 0) {
          oldOrders.unshift(addedOrders)
        }
        setOrders(...oldOrders);
      });
    return () => {
      unsubscribe()
    }
  }, [limit]);

1 个答案:

答案 0 :(得分:3)

你正在改变状态。

  1. let oldOrders = orders; 不会创建数组的副本。它复制引用。
  2. setOrders(...oldOrders); 没有意义。您将数组作为参数传播,但 setOrders 接受 1 个参数。
  3. 如果您的下一个状态取决于前一个状态,您应该使用 setState 的回调形式
  4. 如果您想添加多个项目而不仅仅是单个数组,则需要有 oldOrders.unshift(...addedOrders);

假设您的其余逻辑是正确的,您的代码应该看起来有点像这样。

useEffect(() => {
  const unsubscribe = firebase
    .firestore()
    .collection("Orders")
    .orderBy("date", "desc")
    .limit(parseInt(limit, 10))
    .onSnapshot((snapshot) => {
      // use callback form to avoid relying on stale state
      setOrders((orders) => {
        let oldOrders = [...orders]; // create new array
        let addedOrders = [];

        snapshot.docChanges().forEach((change) => {
          if (change.type === "added") {
            addedOrders.push({ ...change.doc.data(), id: change.doc.id });
          }
          if (change.type === "modified") {
            oldOrders[oldOrders.findIndex((x) => x.id === change.doc.id)] = {
              ...change.doc.data(),
              id: change.doc.id,
            };
          }
          if (change.type === "removed") {
            oldOrders.splice(
              oldOrders.findIndex((x) => x.id === change.doc.id)
            );
          }
        });
        if (addedOrders.length > 0) {
          oldOrders.unshift(...addedOrders);
        }

        return oldOrders;
      });
    });
  return () => {
    unsubscribe();
  };
}, [limit]);