反应setState数组问题

时间:2020-10-22 14:11:01

标签: javascript reactjs firebase

我下面有这个JavaScript代码:

const getProducts = () => {
        votationRef
            .child(moment().format('yyyy-MM-DD'))
            .once('value').then((snapshot) => {
                try {
                    var productsId = snapshot.val();
                    productsId.map((item) => {
                        productsRef
                            .child(item)
                            .once('value')
                            .then((snapshot) => {
                                setProducts([...products, snapshot.val()]);
                            })
                    })
                } catch (e) {
                    console.log('ERROR', e.message)
                }
            })
    }

简而言之,在DOM完成加载之前,使用getProducts钩子调用了函数useEffect

此功能的任务是(按每个productsId检索存储在我的Firebase RT DB中的每个产品的详细信息,并将它们放入状态数组(setProducts)。

最终的products数组结果在我的JSX中只是显示为“段落列表”。这是代码:

products.map((item) => {
    return <p>{item.name}</p>
})

有人可以向我解释为什么在以上过程结束时我的React状态products仅包含Firebase“产品”文档节点中最后一个产品的详细信息吗?

当前,我的firebase“产品”文档节点包含以下数据:

"products" : {
    "-MK-CnXnTYbyYm5eyYBK" : {
      "coverImg" : "https://firebasestorage.googleapis.com/v0/b/onebidup.appspot.com/o/images%2FcoverImages%2F32a01e12-e7a2-44df-ac62-5d5eac00d031.jpg?alt=media&token=7b9b8304-c0b1-4123-85fd-b0fe4096d3d0",
      "description" : "Audio che riempie la stanza - I cinque altoparlanti offrono bassi potenti, medi dinamici e alti nitidi",
      "maxVote" : 5,
      "name" : "Echo Studio - Altoparlante intelligente",
      "price" : "189.99"
    },
    "-MKFOYfuAdK8Fo4l-aiV" : {
      "coverImg" : "https://firebasestorage.googleapis.com/v0/b/onebidup.appspot.com/o/images%2FcoverImages%2F8e1edf42-562b-4a05-8180-b320968b1024.jpg?alt=media&token=ffad077c-014c-4a60-aab0-edb2cbe526f5",
      "description" : "La serie Q64 è una variante di colore silver della serie Q60 a cui aggiunge il telecomando Premium Metal One Remote e la tecnologia di controllo dell’immagine Ultimate UHD Dimming",
      "name" : "Samsung QE55Q64RATXZT Serie Q64R QLED Smart TV 55\", Ultra HD 4K, Wi-Fi, Silver, 2019",
      "price" : "669"
    },
    "-MKFOsBlMmFS5wnBk8jr" : {
      "coverImg" : "https://firebasestorage.googleapis.com/v0/b/onebidup.appspot.com/o/images%2FcoverImages%2Fa7247e86-b745-4806-8e93-1de733e4f698.jpg?alt=media&token=4b0adf1c-9a90-4da7-9c43-5db40d80ee76",
      "description" : "Splendidamente progettato e costruito per durare - elegante, pratico e affidabile",
      "name" : "Segway-Ninebot ES4 Monopattino Elettrico",
      "price" : "773"
    },
    "-MKFPAewl96EKp3noj2J" : {
      "coverImg" : "https://firebasestorage.googleapis.com/v0/b/onebidup.appspot.com/o/images%2FcoverImages%2F1943a11f-d1ee-4188-9aa9-af0d42466d11.jpg?alt=media&token=f6e1f9ae-7632-406e-acde-5554c45d5ee4",
      "description" : "Sony PS4 PRO PlayStation Gamma Chassis + PS Live Card 20€, 4K HDR, 1 TB [Esclusiva Amazon.it]",
      "name" : "Sony PS4 PRO PlayStation",
      "price" : "419"
    },
    "-MKFPY6pWSPGUfTGIUuH" : {
      "coverImg" : "https://firebasestorage.googleapis.com/v0/b/onebidup.appspot.com/o/images%2FcoverImages%2F0fccd324-e03e-4680-8553-688dd1be25bc.jpg?alt=media&token=c695e0af-d2d2-448e-9747-1aaa6910197f",
      "description" : "iRobot Roomba 981 Robot aspirapolvere WiFi, Power-Lifting, 2 spazzole in gomma multi-superficie, Adatto per peli, Tecnologia Dirt Detect, pulizia a 3 fasi, programmabile con app, Compatibile Alexa",
      "name" : "iRobot Roomba 981",
      "price" : "538.80"
    }
  }

1 个答案:

答案 0 :(得分:1)

问题在于products是一个空数组,即使在您调用之后:

setProducts([...products, snapshot.val()])

要基于先前的值,您必须使用回调变量:

setProducts(products => [...products, snapshot.val()])

主要问题是setProducts在下一次渲染时更新products。它不会影响products的当前值。通过使用回调,新值将传入并可以使用。

useState文档中对此行为进行了描述:

功能更新

如果使用先前状态计算了新状态,则可以将函数传递给setState。该函数将接收先前的值,并返回更新的值。这是同时使用setState两种形式的计数器组件的示例:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

“ +”和“-”按钮使用功能形式,因为更新后的值基于先前的值。但是“重置”按钮使用常规形式,因为它始终将计数设置回初始值。

如果您的更新函数返回的值与当前状态完全相同,则随后的重新渲染将被完全跳过。