javascript - How can I escape React useEffect infinite loop? - Stack Overflow

I wrote a code that receives the api through React Hook and calls the api again in the child ponent by

I wrote a code that receives the api through React Hook and calls the api again in the child ponent by passing the id when clicking. However, there seems to be a problem in settingState with arrow function in useEffect or onClick of child ponent.

I would appreciate it if you could give me an answer on how to fix it.

Users.js

import axios from 'axios';
import React, { useState, useEffect } from 'react';
import UserInfo from './UserInfo';


function Users() {
    const [users, setUsers] = useState(null)
    const [loding, setLoding] = useState(false)
    const [error, setError] = useState(false)


    const [userId, setUserId] = useState(null)

    const fetchUsers = async () => {
        try {
            setUsers(null)
            setError(null);
            setLoding(true)

            const respnse = await axios.get('')

            setUsers(respnse)
        } catch (e) {
            setError(e)
        }
        setLoding(false)
    };

    useEffect(() => {
        fetchUsers();
    }, []);

    if (loding) return <div>loading...</div>
    if (error) return <div>error....</div>
    if (!users) return null;

    return (
        <>
            <ul>
                {
                    users.data.map(user =>
                        <li key={user.id} onClick={() => setUserId(user.id)} >
                            {user.username} ({user.name})
                        </li>
                    )
                }
            </ul>
            <button onClick={fetchUsers}>
                reload
            </button>
            {userId && <UserInfo id={userId} />}
        </>
    );
}

export default Users;

UserInfo.js

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

function UserInfo({ id }) {

    const [userInfo, setUserInfo] = useState(null)

    async function getUsersAPI() {
        try {
            const response = await axios.get(`/${id}`)
            setUserInfo(response)
        } catch (e) {

        }
    }

    useEffect(() => {
        getUsersAPI()
    }, [userInfo])


    if (!userInfo) {
        return null;
    }

    const { data } = userInfo

    return (
        <>
            <h2>{data.username}</h2>
            <p>
                <b>email: </b>{data.email}
            </p>
        </>
    );
}

export default UserInfo;

I wrote a code that receives the api through React Hook and calls the api again in the child ponent by passing the id when clicking. However, there seems to be a problem in settingState with arrow function in useEffect or onClick of child ponent.

I would appreciate it if you could give me an answer on how to fix it.

Users.js

import axios from 'axios';
import React, { useState, useEffect } from 'react';
import UserInfo from './UserInfo';


function Users() {
    const [users, setUsers] = useState(null)
    const [loding, setLoding] = useState(false)
    const [error, setError] = useState(false)


    const [userId, setUserId] = useState(null)

    const fetchUsers = async () => {
        try {
            setUsers(null)
            setError(null);
            setLoding(true)

            const respnse = await axios.get('https://jsonplaceholder.typicode./users')

            setUsers(respnse)
        } catch (e) {
            setError(e)
        }
        setLoding(false)
    };

    useEffect(() => {
        fetchUsers();
    }, []);

    if (loding) return <div>loading...</div>
    if (error) return <div>error....</div>
    if (!users) return null;

    return (
        <>
            <ul>
                {
                    users.data.map(user =>
                        <li key={user.id} onClick={() => setUserId(user.id)} >
                            {user.username} ({user.name})
                        </li>
                    )
                }
            </ul>
            <button onClick={fetchUsers}>
                reload
            </button>
            {userId && <UserInfo id={userId} />}
        </>
    );
}

export default Users;

UserInfo.js

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

function UserInfo({ id }) {

    const [userInfo, setUserInfo] = useState(null)

    async function getUsersAPI() {
        try {
            const response = await axios.get(`https://jsonplaceholder.typicode./users/${id}`)
            setUserInfo(response)
        } catch (e) {

        }
    }

    useEffect(() => {
        getUsersAPI()
    }, [userInfo])


    if (!userInfo) {
        return null;
    }

    const { data } = userInfo

    return (
        <>
            <h2>{data.username}</h2>
            <p>
                <b>email: </b>{data.email}
            </p>
        </>
    );
}

export default UserInfo;
Share Improve this question edited Aug 7, 2021 at 8:19 Drew Reese 204k18 gold badges246 silver badges274 bronze badges asked Aug 7, 2021 at 8:14 dev_Odev_O 1633 silver badges13 bronze badges 3
  • 3 why is userInfo in the dependency array for useEffect? – ksav Commented Aug 7, 2021 at 8:17
  • It is implemented so that it can have useinfo information through the api. If I'm wrong, please give me another answer. – dev_O Commented Aug 7, 2021 at 8:21
  • 1 getUsersAPI updates the userInfo state, which as a dependency, triggers the useEffect hook's callback to again call getUsersAPI, thus creating a render loop. When do you actually want the effect in the child to run? If I had to guess, it should be the id prop that is passed since that is referenced in the getUsersAPI call. – Drew Reese Commented Aug 7, 2021 at 8:21
Add a ment  | 

3 Answers 3

Reset to default 4

It seems like you want id to be a useEffect dependency instead of userInfo.

Otherwise every time userInfo changes the effect will run, it will call getUsersAPI which in turns sets the value of userInfo when axios resolves (thus causing an infinite loop).

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

    function UserInfo({ id }) {
        const [userInfo, setUserInfo] = useState(null)
        async function getUsersAPI() {
            try {
                const response = await axios.get(`https://jsonplaceholder.typicode./users/${id}`)
                setUserInfo(response)
            } catch (e) {}
        }

        useEffect(() => {
            getUsersAPI()
        }, [id])

        if (!userInfo) {
            return null;
        }

        const { data } = userInfo

        return (
            <>
                <h2>{data.username}</h2>
                <p>
                    <b>email: </b>{data.email}
                </p>
            </>
        );
    }

    export default UserInfo;

this problem is due to the fact that you have set userInfo as a dependency for useEffect dependency array! every time this ponent renders, useEffect will call your API and it changes the value of userInfo, so you encounter with infinite loop!

The problem is in the UserInfo.js file. In these lines:

useEffect(() => {
    getUsersAPI()
}, [userInfo])

You fetch userInfo but then setUserInfo(response) again which cause useEffect to run again.

If might want to leave it as:

useEffect(() => {
    getUsersAPI()
}, [])

So the useEffect only run once. Or you want it to reflect your last userId from props then put userId to the dependency array:

useEffect(() => {
    getUsersAPI()
}, [id])

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745348118a4623657.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信