Home > database >  useEffect Object dependency infinite loop - ReactJS
useEffect Object dependency infinite loop - ReactJS

Time:05-10

I have a State in Context with Object. I am running a async function in the useEffect and passing my object state as dependency.

I passed the state object as dependency because i want to re-render the component when values of settings object changes.

But it causes an infinite loop.

Update:
Let me clear my question more.
In my useEffect, I am calling my async function addTextItem() which calls the function finalPrice and it updates the state, but this way it causes infinite loop.
On other hand, If i call finalPrice in the useEffect directly instead of calling addTextItem then there is no infinite loop but it is also updating the state, right? then how this could be. & I need a solution as i have tried everything and now totally stuck.

Here is the code:

export default function CustomizerState(props) {
    const initialText = "Hello"
    const initialSize = {
        x: REACT_APP_SIZE_X,
        y: REACT_APP_SIZE_Y
    }
    const initialTextItem = {
        id: generateID(),
        text: "Hello",
        font: fonts[0].value,
        size: initialSize,
        color: colors[0],
        backplate: "cut-sharp",
        uvPrint: false,
        quantity: 1,
        neonPrice: 0,
        backplatePrice: 0,
        neonPower: 0,
        totalPrice: 0
    }
    const [settings, setSettings] = useState({
        textItems: [],
        libraryItems: [],
        ownDesigns: [],
        accessories: [
            // My Objects here
        ],
        finalPrice: 0
    })

    const addTextItem = async () => {
        const pathLength = await textToPath(initialText, initialSize.x)
        const { backplatePrice, neonPrice, neonPower, totalPrice } = calculateSvgPrice(pathLength)
        const id = generateID()

        const newItems = [
            ...settings.textItems,
            {...initialTextItem, id, backplatePrice, neonPrice, neonPower, totalPrice}
        ]
        
        finalPrice("textItems", newItems)
    }

    const finalPrice = (itemType = null, items = null) => {
        const textItemsPrice = getTotalPrice()
        const libraryItemsPrice = getTotalPrice("libraryItems")
        const accessoriesPrice = getTotalPrice("accessories", "unitPrice")

        const finalPrice = textItemsPrice   libraryItemsPrice   parseInt(accessoriesPrice)

        if (itemType === null) {
            setSettings((prevState) => (
                {...prevState, finalPrice}
            ))
            return false
        }

        setSettings((prevState) => (
            {...prevState, [itemType]: items, finalPrice}
        ))
    }

    useEffect(() => {
        // It will add first initial form item
        addTextItem()
    }, [JSON.stringify(settings)])

    return (
        <CustomizerContext.Provider value={{settings, addTextItem}}>
            {props.children}
        </CustomizerContext.Provider>
    )
}

enter image description here

I have google and tried the solutions, but nothing worked for me. Can someone help me to fix this issue? I am stuck....

CodePudding user response:

Check the useEffect hook documentation. The array passed in the second argument array is the dependency array:

useEffect(() => {
    //hook code   
}, []);

The dependency array will make the hook code execute everytime any variable of the array changes. In your case you are changing the depency item settings in the call itself producing an infinite loop.

CodePudding user response:

I forgot that when re-rendering happens, it also runs useEffect obviously and it causes setState again and again.
I managed to fix this by creating a state named initialItemCount with 0 initial value. I am checking if that state value is 0 then run addTextItem which will add my initial form item and updates the final price, but if the value 1 then only run the finalPrice function.

const [initialItemCount, setInitialItemCount] = useState(0)
useEffect(() => {
    if (initialItemCount === 0) {
        addTextItem()
        setInitialItemCount(1)
    }
    
    if (initialItemCount === 1) {
        finalPrice()
    }
}, [JSON.stringify(settings)])

Finally, inner peace.

  • Related