masroore
masroore

Reputation: 10135

useEffect called multiple times

I have the following reactjs code:

import React, { useState, useEffect } from 'react'

const Test = () => {
    const [counter, setCounter] = useState(0)

    useEffect(() => {
        const data = localStorage.getItem('counter')
        setCounter(parseInt(data, 10))
        console.log('init', data)
    }, [])

    useEffect(() => {
        localStorage.setItem('counter', counter)
        console.log('changed', counter)
    }, [counter])

    const addCounter = () => {
        setCounter((c) => c + 1)
        console.log('added', counter)
    }

    return (
        <div>
            {counter}
            <button onClick={addCounter}>+</button>
        </div>
    )
}


function App() {
    return (
        <div className='App'>
            <Test />
        </div>
    )
}

The useEffect() hooks are being called multiple times. The states are persisted in localStorage. But upon page refresh, the states reset to default values:

init 4          <--- counter was incremented to 4 at previous session
changed 0       <-- counter is reset to 0??
init 0          <-- this should not appear
changed 0 

What am I doing wrong?

Upvotes: 1

Views: 2864

Answers (1)

DINK74
DINK74

Reputation: 547

You can use this boilerplate to avoid repeated renders while in <StrictMode>

function App() {

    const [success, setSuccess] = useState(false);

    const isMounted = useRef(false);

    useEffect(() => {
        console.log('started');
        if (isMounted.current) {
            console.log('mounted');
        } else {
            console.log('mounting');
            isMounted.current = true;
        }
    }, [success]);

    const handleClick = (e) => {
        setSuccess(!success);
    }

    return (
        <div className="App">
            <header className="App-header">
                <button className="button" onClick={handleClick}>Action</button>
            </header>
        </div>
    );
}

Upvotes: 2

Related Questions