Thinking of a name
Thinking of a name

Reputation: 57

useReducer with useContext hook behaves weirdly, and runs and infinite loop

I am trying to make a React project which fetches data from an API, and I'm trying to use useReducer hook with useContext from an external file. Folder Structure:

reducer.js:

    const reducer = (currentState, action)=>{
    switch(action.type){
        case 'setBreedList':
            // console.log('setBreedList ran')
            return {...currentState, breedList: [...currentState.breedList, action.payload]}
            // return currentState
            // return {...currentState.breedList, action.payload}
        default:
            return currentState
    }
}
export default reducer

context.js

import React, {useContext, useReducer} from 'react';
import reducer from './reducer';

const AppContext = React.createContext();

const initalState = {
    breedList: [],
    imageList: []
}

const AppProvider = ({children})=>{
    const [state, dispatch] = useReducer(reducer, initalState);

    const fetchAllBreeds = ()=>{
        fetch('https://dog.ceo/api/breeds/list/all')
            .then(res=>res.json())
            .then(data=>dispatch({type: 'setBreedList', payload: data}))
    }

    return (
        <AppContext.Provider value={{...state, fetchAllBreeds}}>
            {children}
        </AppContext.Provider>
    )
}

export const useGlobalContext = ()=>{
    return useContext(AppContext)
}

export {AppContext, AppProvider}

and this is index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {AppProvider} from './utils/context';

ReactDOM.render(
  <React.StrictMode>
    <AppProvider>
      <App />
    </AppProvider>  
  </React.StrictMode>,
  document.getElementById('root')
);

and finally, this is Input.jsx, where I call the fetchAllBreeds function:

import React from 'react'
import {useGlobalContext} from '../utils/context'

const Input = () => {
    const {state, fetchAllBreeds} = useGlobalContext();
    fetchAllBreeds();
    console.log('hello')
    return (
        <div>
            <p>hello</p>
        </div>
    )
}

export default Input

Now, when I try to call the fetchAllBreeds function in the Input.jsx file above, it prints on the console, 'hello', endlessly. I can't figure out why this is happening and I have tried some different things, but the result is the same. Will be grateful to your help.

Upvotes: 0

Views: 329

Answers (1)

Gulam Hussain
Gulam Hussain

Reputation: 1763

Input component is calling fetchAllBreeds function, that will update the context value which in turn will re-render Input component, hence fetchAllBreeds will re-run. Don't call any method inside the component body which will cause re-renders.

Use useEffect hook inside Input component. which will execute only once.

import React, {useEffect} from 'react'
import {useGlobalContext} from '../utils/context'

const Input = () => {
    const {state, fetchAllBreeds} = useGlobalContext();
    
    useEffect(()=>{
        fetchAllBreeds();
    }, [])
    
    return (
        <div>
            <p>hello</p>
        </div>
    )
}

export default Input

Upvotes: 4

Related Questions