Search code examples
javascriptreactjsaxiosreact-hooksuse-effect

How can I make useEffect react hook rerender based on a variable value?


So I got this component:

export default function () {
    const [todos, setTodos] = useState([]);


    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, []);

    console.log(todos);

    return (
        <div>
            ...
        </div>
    );
}

I am using the useEffect hook to fetch all the todos from the database, and it works fine. The problem is that I don't know how to use useEffect to trigger a rerender anytime I make a modification to the todos array, like adding or deleting or updating. If I supply the useEffect's dependency array with the todos variable I get an infinite loop logging in the console. How can I use useEffect to trigger a rerender anytime the todos array gets updated?


Solution

  • The problem is there is no logic inside the useEffect see this code bellow

        const [todos, setTodos] = useState([]);
    
        useEffect(() => {
            setTodos([1])
        }, [todos])
    

    This will also give an infinite loop. but we are always giving the same value. The problem is when it gets updated the dependency is true so it again starts executing the useEffect(). You have to come up with some concrete logic like length is changed or you can take a new state which is like this bellow

        const [todos, setTodos] = useState([]);
        const [load, setLoad] = useState(false);
    
        useEffect(() => {
            function populateTodos () {
                axios.get(`http://localhost:8000/api/all-todos`)
                    .then(res => setTodos(res.data))
                    .catch(err => console.log(err));
            }
    
            populateTodos();
        }, [load])
    
        console.log(todos)
        return (
            <div>
                <button
                onClick={() => {
                    todos.push(1)
                    setLoad(!load)
                }}
                >cilck</button>
            </div>
        );