1

I have a multipage application. When i click between dashboard/global and dashboard/my-posts useEffect is invoked. Thus, my application is constantly calling my fetch and taking a while to load.

Is there a way to only invoke useEffect when new data is being has been found?

I tried adding myRecipes and AllRecipes to the useEffect dependency but track promise's loading indictator is running infinitely.

import React, {
  useState, useEffect, useContext, useMemo,
} from 'react';
import { v1 as uuidv1 } from 'uuid';
import { trackPromise } from 'react-promise-tracker';
import LoadingIndicator from '../utils/LoadingIndicator';
import DashboardHeader from './DashboardHeader';
import '../App.css';
import Post from './Post';
import CreateForm from '../create-recipe/CreateForm';
import RecipeService from '../../service/RecipeService';
import { AuthContext } from '../../context/AuthContext';

export default function Dashboard() {
  const { isAuthenticated } = useContext(AuthContext);
  const [allRecipes, setAllRecipes] = useState([]);
  const [myRecipes, setMyRecipes] = useState([]);
  const currentUrl = window.location.pathname;

  useEffect(() => {
    if (currentUrl === '/dashboard/global') {
      trackPromise(
        RecipeService.getAllRecipes()
          .then((data) => {
            setAllRecipes(data);
          }),
      );
    } else if (currentUrl === '/dashboard/my-posts' && isAuthenticated === true) {
      trackPromise(
        RecipeService.getRecipes()
          .then((data) => {
            setMyRecipes(data);
          }),
      );
    }
  }, [currentUrl, allRecipes, myRecipes]);

  return (
    <>
      <div className="dashboard">
        <DashboardHeader />
        {currentUrl === '/dashboard/my-posts' && !isAuthenticated
          ? <h2 className="dashboard__unauthenticated-msg">Please Login To See Your Recipes</h2>
          : null}
        <div className="created-posts">
          {currentUrl === '/dashboard/global' && allRecipes
            ? allRecipes.map((recipe) => <Post recipe={recipe} key={uuidv1()} />)
            : null}
          {currentUrl === '/dashboard/my-posts' && myRecipes.recipes
            ? myRecipes.recipes.map((recipe) => <Post recipe={recipe} key={uuidv1()} />)
            : null}
          {myRecipes.recipes && allRecipes
            ? null : <LoadingIndicator />}
        </div>
        {currentUrl === '/dashboard/create' ? <CreateForm /> : null}
      </div>
    </>
  );
}

3
  • 1
    Can you remove allRecipes and myRecipes from the dependency list? setAllRecipes is probably causing allRecipes to change, which in turn causes the useEffect hook to be triggered. Commented Feb 5, 2021 at 21:13
  • I tried that in the first place. But what if i wanted useEffect to check if whether allRecipes and myRecipes changed? Commented Feb 5, 2021 at 21:18
  • 1
    Is this useEffect hook the only place where allRecipes or myRecipes would be changed? If so, is there a reason you couldn't check within this hook in the then() sections? Commented Feb 5, 2021 at 21:24

2 Answers 2

1

If you want to call a function depending on source data whether it changed or not, I would recommend you to use selectors with redux.

In short, selectors are memoized functions that detect changes to the current parameter.

Sign up to request clarification or add additional context in comments.

2 Comments

I agree... i was going to start with redux anyways, so perhaps i will do so now. But how is that different from using react's useMemo.. Im just making a guess, that the difference between redux and usememo is that redux is global?
I think you’re a little confused. You meant useContext instead of useMemo, right? Anyway, I do recommend you to read the React docs, especially about hooks: reactjs.org/docs/hooks-intro.html. Redux is used to store data of your app. It’s easy to understand its concept. You can also find information about it: redux.js.org/tutorials/essentials/part-1-overview-concepts.
1

A better architecture could help you to solve the issues with this component. You should use a router and load different components when the URL changes. Then you can make the appropriate API call, and render the appropriate JSX for that page.

AllRecipes and myRecipes should not be dependencies of that useEffect, because when it is invoked it will updated those states and trigger itself again.

2 Comments

that could be an option, but given that both have the same jsx layout/css, i feel like there isnt a point to duplicate my code if i know it can be done in one.
you would create a shared component and import it into each of those containers. Then your code is shared, but not duplicated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.