So I have a page in react that is constantly rendering , say for eg. when I console log I can see that getting logged infinitely in a loop. is it some hook on some inner components that is getting rendered constantly I can't figure out
When i comment out
<CartContainer line_items = {line_items} />
it still doesnt solve the issue.
could useCartState() context be the issue?
Below is the page
import React, {useEffect} from "react"
import { CartContainer, NavigationBar } from "../components"
import {useRouter} from 'next/router'
import { useCartState } from "../context/Cart"
import { QuestionMarkCircleIcon } from '@heroicons/react/solid'
const getPaymentAPIStatus = async () =>
{
const response = await fetch("https://api.nowpayments.io/v1/status")
const data = await response.json()
}
const CartPage = () => {
const router = useRouter();
const {line_items, subtotal, total_items} = useCartState() // to get cart details --anaya
const isEmpty = line_items.length === 0
if(isEmpty)
return(
<div>
<NavigationBar/>
<p>Your cart is empty. Please add some items</p>
</div>
)
else {
return(
<div>
<NavigationBar/>
<div className="bg-white">
<div className="max-w-2xl mx-auto pt-16 pb-24 px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<h1 className="text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl">Shopping Cart</h1>
<form className="mt-12 lg:grid lg:grid-cols-12 lg:gap-x-12 lg:items-start xl:gap-x-16">
<section aria-labelledby="cart-heading" className="lg:col-span-7">
<h2 id="cart-heading" className="sr-only">
Items in your shopping cart
</h2>
<CartContainer line_items = {line_items} />
</section>
{/* Order summary */}
<section
aria-labelledby="summary-heading"
className="mt-16 bg-gray-50 rounded-lg px-4 py-6 sm:p-6 lg:p-8 lg:mt-0 lg:col-span-5"
>
<h2 id="summary-heading" className="text-lg font-medium text-gray-900">
Order summary
</h2>
<dl className="mt-6 space-y-4">
<div className="flex items-center justify-between">
<dt className="text-sm text-gray-600">Subtotal</dt>
<dd className="text-sm font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="flex items-center text-sm text-gray-600">
<span>Shipping estimate</span>
<a href="#" className="ml-2 flex-shrink-0 text-gray-400 hover:text-gray-500">
<span className="sr-only">Learn more about how shipping is calculated</span>
<QuestionMarkCircleIcon className="h-5 w-5" aria-hidden="true" />
</a>
</dt>
<dd className="text-sm font-medium text-gray-900">Free</dd>
</div>
<div className="border-t border-gray-200 pt-4 flex items-center justify-between">
<dt className="text-base font-medium text-gray-900">Order total</dt>
<dd className="text-base font-medium text-gray-900">{subtotal.formatted_with_symbol}</dd>
</div>
</dl>
<div className="mt-6">
<button
type="submit"
className="w-full bg-indigo-600 border border-transparent rounded-md shadow-sm py-3 px-4 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-50 focus:ring-indigo-500"
>
Checkout
</button>
</div>
<div className="mt-6 text-sm text-center">
<p>
or{' '}
<a href ={`${router.basePath}/ChooseProduct`} className="text-indigo-600 font-medium hover:text-indigo-500">
Continue Designing<span aria-hidden="true"> →</span>
</a>
</p>
</div>
</section>
</form>
</div>
</div>
</div>
)
}
}
export default CartPage
How do i solve this? Thanks in advance!
Adding useCartState as requested
import {createContext, useEffect, useContext, useReducer} from 'react'
import {commerce} from '../../lib/commerce'
//need to correct this file to be a tsx file in the future
//Provides a context for Cart to be used in every page
const CartStateContext = createContext()
const CartDispatchContext = createContext()
const SET_CART = "SET_CART"
const initialState = {
total_items: 0,
total_unique_items: 0,
subtotal:[],
line_items: [{}]
}
const reducer = (state,action) => {
switch(action.type){
case SET_CART:
return { ...state, ...action.payload }
default:
throw new Error(`Unknown action: ${action.type}` )
}
}
export const CartProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const setCart = (payload) => dispatch({type: SET_CART, payload})
useEffect(() => {
getCart()
},[state]) // Getting the page to be rendered whenever the cart objects are changed
const getCart = async() => {
try {
const cart = await commerce.cart.retrieve()
setCart(cart)
} catch (error){
console.log("error")
}
}
return (
<CartDispatchContext.Provider value = {{setCart}}>
<CartStateContext.Provider value = {state}>
{children}
</CartStateContext.Provider>
</CartDispatchContext.Provider>
)
}
export const useCartState = () => useContext (CartStateContext)
export const useCartDispatch = () => useContext (CartDispatchContext)
CodePudding user response:
The problem here is that you have a useEffect
with state
as a dependency, meaning that every time the state value is altered, the getCart
function gets called.
Meanwhile, getCart
sets the state within it.
Therefor, it creates a cycle where getCart
sets the state, the useEffect
callback runs as a result, getCart
gets called again, sets the state again, and so on.
The bottom line is that you can not set the state inside of a function and call that function every time the state value is altered.