1

Been pulling my hair over this one the whole day and I feel like I've tried pretty much everything, even a dozen StackOverflow answers, to no avail...

tldr; given a specific trigger which happens externally (and just fine) I'm trying to get data from Firestore and update local state (an array) with this new data. Now I know that for React to re-render when updating an array, it will disregard the contents and considers the reference to that array only. The problem is, React seems to not trigger a re-render even when setting the state to a completely new array.

Here is the code:

const Recipe = (irrelevantProps) => {
  // A few other state hooks here, not shown for clarity's sake
  const [ingredients, setIngredients] = useState<IngredientType[]>([]);

  useEffect(() => {
    const getIngredientsDocs = () => {
      return ingredientsRefs.map(async (ingredientRef) => {
        const docRef = doc(firestore, "ingredients", ingredientRef.id);
        const docData = (await getDoc(docRef)).data() as IngredientType;
        return docData;
      });
    };

    Promise.all(getIngredientsDocs()).then((newIngredients) => {
      // I would assume updating the state with a new array would trigger a re-render, but it doesn't
      setIngredients(newIngredients);
    });
  }, [externalTrigger]);

For what it's worth, I'm pretty sure everything else is working as expected.

Any hints, suggestions, tips or downright solutions will be VERY much appreciated.

To whomever may read this, thanks a ton regardless!

  • 1
    Just because it is worth confirming, if you do `console.log` right before your setIngredients, can you confirm that it is what you expect ? that is are you sure that the issue is with setIngredients not updating as opposed to the logic generating the values incorrectly ? – ed__ Oct 14 '22 at 18:10
  • Yeah I'd actually just manually set the array in the useEffect without any other logic to see if that's really what's going on. Might be an issue with the await, promise, bad data, etc – Nikki9696 Oct 14 '22 at 18:12
  • above points or just see logging `getIngredientsDocs()` if it's giving an expected array – KcH Oct 14 '22 at 18:17
  • 2
    Check your assumptions: 1) is externalTrigger changing, causing useEffect to actually run? 2) are you actually invoking `setIngredients`? 3) Is the value you're passing to `setIngredients` the one you want? You can either use `console.log` statements at the start of `useEffect` and right above `setIngredients` (logging out the value of `newIngredients`), or even better use the debugger. Maybe `Promise.all` never resolves? Maybe `newIngredients` is an empty array, or some other value that *is* getting set but is the same value as before, so no re-render happens. Just some ideas, good luck! – Nathan Oct 14 '22 at 18:20

2 Answers2

0

I don't have enough reputation points to leave a comment, so I will just do it here (sorry if that's poor etiquette) -- One suggestion I have is to comment out the code within useEffect and just put setIngredients(newIngredients); in its place to see if re-renders work in that scenario.

I've also seen people use a local variable to refer to this outside of a Promise which seems to work though in this case they are using a class component while yours is functional.

hiptip
  • 1
0

Thanks for your help everyone. You were all right in having me test my assumptions. Turns out the new data was fine and the re-rendering was happening too. The problem was a couple levels deeper where a component wasn't updating another state. :facepalm: Lesson learned!

  • Welcome to Stack Overflow! Please don't post an answer to respond to another answer. That's what comments are for. – pigrammer Oct 18 '22 at 18:22