更新 useContext 的值时,组件不会重新呈现
Component not re rendering when value from useContext is updated
我正在使用 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>
)
我希望购物车组件会在更新数组时显示数组的新长度,但它会保持不变,直到我导航到另一个页面时重新呈现该组件。每次更新上下文中的数组时,我都需要它重新渲染。
问题很可能是您正在改变数组(而不是设置新数组),因此 React 使用浅层相等将数组视为相同。
更改 addOrder
分配新数组的方法应该可以解决此问题:
const addToOrder = (idToAdd, quantityToAdd = 1) =>
setProducts([
...products,
{
id: idToAdd,
quantity: quantityToAdd
}
]);
正如@skovy所说,如果你想改变原来的数组,根据他的回答有更优雅的解决方案。
setProducts(prevState => {
prevState[0].id = newId
return [...prevState]
})
@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
我会厌倦在大型应用程序上执行此操作,因为重新呈现会导致严重的性能问题。在我的例子中,它是一个很小的两页小程序,所以一些浪费的重新渲染对我来说是可以的。
我正在使用 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>
)
我希望购物车组件会在更新数组时显示数组的新长度,但它会保持不变,直到我导航到另一个页面时重新呈现该组件。每次更新上下文中的数组时,我都需要它重新渲染。
问题很可能是您正在改变数组(而不是设置新数组),因此 React 使用浅层相等将数组视为相同。
更改 addOrder
分配新数组的方法应该可以解决此问题:
const addToOrder = (idToAdd, quantityToAdd = 1) =>
setProducts([
...products,
{
id: idToAdd,
quantity: quantityToAdd
}
]);
正如@skovy所说,如果你想改变原来的数组,根据他的回答有更优雅的解决方案。
setProducts(prevState => {
prevState[0].id = newId
return [...prevState]
})
@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
我会厌倦在大型应用程序上执行此操作,因为重新呈现会导致严重的性能问题。在我的例子中,它是一个很小的两页小程序,所以一些浪费的重新渲染对我来说是可以的。