更新useContext的值后,组件不会重新呈现

时间:2019-09-08 02:55:05

标签: reactjs gatsby react-context

我正在使用React的上下文API存储项目数组。有一个组件可以通过useContext()访问此数组,并显示该数组的长度。还有另一个组件可以访问通过useContext更新此数组的函数。将项目添加到数组时,组件不会重新渲染以反映数组的新长度。当我导航到应用程序中的另一个页面时,该组件会重新渲染并反映数组的当前长度。每当上下文中的数组发生更改时,我都需要重新渲染组件。

我尝试使用Context.Consumer而不是useContext,但是当更改数组时,它仍然不会重新呈现。

//orderContext.js//

import React, { createContext, useState } from "react"

const OrderContext = createContext({
  addToOrder: () => {},
  products: [],
})

const OrderProvider = ({ children }) => {
  const [products, setProducts] = useState([])

  const addToOrder = (idToAdd, quantityToAdd = 1) => {
    let newProducts = products
    newProducts[newProducts.length] = {
      id: idToAdd,
      quantity: quantityToAdd,
    }
    setProducts(newProducts)
  }

  return (
    <OrderContext.Provider
      value={{
        addToOrder,
        products,
      }}
    >
      {children}
    </OrderContext.Provider>
  )
}

export default OrderContext
export { OrderProvider }
//addToCartButton.js//

import React, { useContext } from "react"
import OrderContext from "../../../context/orderContext"

export default ({ price, productId }) => {
  const { addToOrder } = useContext(OrderContext)

  return (
    <button onClick={() => addToOrder(productId, 1)}>
      <span>${price}</span>
    </button>
  )
}

//cart.js//

import React, { useContext, useState, useEffect } from "react"
import OrderContext from "../../context/orderContext"

export default () => {
  const { products } = useContext(OrderContext)
  return <span>{products.length}</span>
}
//gatsby-browser.js//

import React from "react"
import { OrderProvider } from "./src/context/orderContext"
export const wrapRootElement = ({ element }) => (
   <OrderProvider>{element}</OrderProvider>
)

我希望在更新数组时,购物车组件会显示该数组的新长度,但是当我导航到另一个页面时,直到重新渲染该组件之前,它都保持不变。每当上下文数组更新时,我都需要重新渲染。

3 个答案:

答案 0 :(得分:1)

问题很可能是您对数组进行了突变(而不是设置新数组),因此React使用浅等式将数组视为相同。

更改您的addOrder方法来分配新数组应该可以解决此问题:

const addToOrder = (idToAdd, quantityToAdd = 1) =>
  setProducts([
    ...products,
    {
      id: idToAdd,
      quantity: quantityToAdd
    }
  ]);

Edit context-arrays

答案 1 :(得分:1)

正如@skovy所说,如果您想更改原始数组,则可以根据他的答案找到更优雅的解决方案。

setProducts(prevState => {
  prevState[0].id = newId
  return [...prevState]
})

答案 2 :(得分:1)

@skovy 的描述帮助我理解为什么我的组件没有重新渲染。

在我的例子中,我有一个包含一个大字典的提供者,每次我更新那个字典时都不会发生重新渲染。

例如:

const [var, setVar] = useState({some large dictionary});

...mutate same dictionary
setVar(var) //this would not cause re-render
setVar({...var}) // this caused a re-render because it is a new object

我会厌倦在大型应用程序上执行此操作,因为重新渲染会导致严重的性能问题。就我而言,它是一个两页的小程序,所以一些浪费的重新渲染对我来说是可以的。