4

I am trying to practice with useReducer and context api but when trying to execute the function that returns the data, I get an infinite loop

reducer.js

const initialStore = {
  disabledAddButton: false,
  disabledDelButton: false,
  user: null,
  total_purchase: 0,
  cart: [],
  tasks: [],
}

const reducer = (state, action) => {
  switch (action.type) {
    case TYPES.USER_GET_TASKS: {
      return {
        ...state,
        tasks: action.payload,
      }
    }
    default:
      return state
   }
 }

UserProvider.js

const UserContext = createContext()

const UserProvider = ({ children }) => {
 
  const [store, dispatch] = useReducer(reducer, initialStore)

const getTasks = async () => {
    try {
      const response = await db.collection('tasks').get()
      const arrayData = response.docs.map(doc => ({
        id: doc.id,
        ...doc.data(),
      }))

      dispatch({
        type: TYPES.USER_GET_TASKS,
        payload: arrayData,
      })
    } catch (error) {
      console.log(error)
    }
  }
const value = {
    store,
    getTasks,
    dispatch,
  }
  return <UserContext.Provider value={value}>{children}</UserContext.Provider>
}

export { UserContext }
export default UserProvider

Tasks.js

const Tasks = () => {
  const { store, getTasks } = useContext(UserContext)
  const { tasks } = store
      
  useEffect(() => {
    getTasks()
  }, [])

  return (
    <div>
      {tasks.map(task => (
        <h2 key={task.id}>{task.name}</h2>
      ))}
    </div>
  )
}

export default Tasks

Basically the problem is when im running getTasks() on tasks component (inside of useEffect) I get infinite loop and I do not know why

Nihil
  • 41
  • 2

1 Answers1

2

This must have something to do with the firebase db because I was not able to replicate the issue with an API fetch.

You can minimize re-renders from the UserProvider by using useMemo and useCallback. Now the getTasks function will only be created once instead of being re-created on every render.

const UserProvider = ({ children }) => {
  const [store, dispatch] = useReducer(reducer, initialStore);

  const getTasks = useCallback(async () => {
    try {
      const response = await db.collection("tasks").get();
      const arrayData = response.docs.map((doc) => ({
        id: doc.id,
        ...doc.data()
      }));
      dispatch({
        type: TYPES.USER_GET_TASKS,
        payload: arrayData
      });
    } catch (error) {
      console.log(error);
    }
  }, [dispatch]);

  const value = useMemo(
    () => ({
      store,
      getTasks,
      dispatch
    }),
    [store, getTasks, dispatch]
  );

  return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};

Hopefully that helps!

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102