How to stop infinite loops?

Viewed 99

this is my component:

const Inscriptions = () => {

    // get state
    const { inscriptions, loading } = useSelector( state => state.user );

    // flag
    const instances = Object.keys(inscriptions).length;
    
    // dispatch
    const dispatch = useDispatch();

    const getInscriptions = useCallback(
        () => dispatch( getInscriptionsAction() ),
        [ dispatch ]
    );
    const cancel = id => dispatch( cancelInscriptionAction(id) );
    const cancelAll = () => dispatch( cancelAllInscriptionAction() );

    useEffect( () => {
            const queryToApi = () => {
                getInscriptions();  
            };
    
            queryToApi();
    }, [ getInscriptions ]);

    if(loading) return null;
    
    // delete item
    const handleClickCancel = id => {...};

    const handleClickCancelAll = () => {...};

    return ( ... );
}
 
export default Inscriptions;

And here it's reducer:

case GET_USER_INSCRIPTIONS:
            return {
                ...state,
                error: false,
                loading: true
            };

        case GET_USER_INSCRIPTIONS_SUCCESS:
            return {
                ...state,
                error: false,
                loading: false,
                inscriptions: action.payload
            };                                  

        case GET_USER_INSCRIPTIONS_FAIL:
            return {
                ...state,
                error: true,
                loading: false, 
                inscriptions: []
            };

My problem is, I have another component with identical logic, but this component goes into infinite looping. Looking up my Redux dev Tools, I see that it perma calls "GET_USER_INSCRIPTIONS" action, i don't know why it doesn't call it once, like I'm missing something happening in the background, but with the other component that doesn't happen, it loads, and once loading is false (when the SUCCESS action is finished)it loads.

I've tried a solution adding a flag bool to the reducer like so:

case GET_USER_INSCRIPTIONS:
            return {
                ...state,
                error: false,
                loading: true,
                flag: false
            };

        case GET_USER_INSCRIPTIONS_SUCCESS:
            return {
                ...state,
                error: false,
                loading: false,
                flag: true,
                inscriptions: action.payload
            };                                  

        case GET_USER_INSCRIPTIONS_FAIL:
            return {
                ...state,
                error: true,
                loading: false, 
                flag: true,
                inscriptions: []
            };

And then changin my useEffect to this:

useEffect( () => {
        if(!loading && !flag) {
            const queryToApi = () => {
                getInscriptions();  
            };
    
            queryToApi();
        }
        
    }, [ getInscriptions, loading, flag ]);

    if(loading) return null;

And works perfect, but I still missing why i have to do this in this component while the other one performs well without this. If someone can take a look and enlighten me please, I'd really appreciate that thank you.

2 Answers

Every time when u call GET_USER_INSCRIPTIONS_SUCCESS action u change the state what`s connected to your component and it calls useEffect again, because dependencies changed

for fix

useEffect( () => {
    if(!loading && !flag) {
        const queryToApi = () => {
            getInscriptions();  
        };

        queryToApi();
    }
}, [ getInscriptions ]);

Okay I solved it, the thing is I had other actions non-referent to the Inscriptions stuff, sharing the same reducer, so that was the interference. I've created an exclusive reducer for managing my inscriptions component. Seems that is the way of redux telling you to module your stuff.

Related