Home > other >  react jsx refuses to show updated state in the ui
react jsx refuses to show updated state in the ui

Time:07-02

I have a diary object with 2 meals

function Magicdiary() {
  const [diary, setDiary] = React.useState<MagicDiaryDay[]>([
    { mealName: "Breakfast", ingredient: null },
    { mealName: "Lunch", ingredient: null },
  ]);

  return (
    <div>
      <p>meal 1: {diary[0].ingredient?.productName}</p>
      <Button onClick={() => console.log(diary[0].ingredient?.productName)}>
        log diary
      </Button>
      {diary.map((meal, index) => {
        return (
          <MealComponentForMagicDiary
            diary={diary}
            setDiary={setDiary}
            index={index}
          />
        );
      })}
    </div>
  );
}

I have selection of ingredients that I call from my backend, and everytime I select current ingredient, I set it to the diary:

// MealComponentForMagicDiary
    useEffect(() => {
      if (hit) {
        const diaryCopy = diary;
        diaryCopy[index].ingredient = {
          productName: hit.productName,
          nutrients: {
            "energy-kcal_serving": hit.calories,
            protein_serving: hit.protein,
            carbohydrates_serving: hit.carbs,
            fat_serving: hit.fats,
          },
        };
        setDiary(diaryCopy);
      }
    }, [hit, selectedHit]);

As you can see meal 1 is empty, but when I log it on the console I can see the correct productName what is the cause of this bug?

enter image description here

CodePudding user response:

From my limited react experience, when funny things like this happen I have a few go-to methods to try. One of them is to call an empty function when passing a function down as a prop. I.e. instead of:

<MealComponentForMagicDiary
            diary={diary}
            setDiary={setDiary}
            index={index}
          />

try:

<MealComponentForMagicDiary
            diary={diary}
            setDiary={() => setDiary}
            index={index}
          />

I'd love to know why this works sometimes, if anybody (does anybody?) understands react properly.

My fingers are crossed that it works for you!

CodePudding user response:

It's hard to say exactly with this given information but I'm inclined to say this:

You're not getting the information you want because when the component renders, it's not there. Take for example this:

<p>meal 1: {diary[0].ingredient?.productName}</p>

You check if ingredient exists but are you sure diary[0] exists? Since you're setting this data elsewhere in a useEffect, I suspect that it's not available at render - even though you can console it.

I suggest using the React Developer Tools to look at your component tree and see what that state looks like when it's rendered.

That's all I can guess without more code.

CodePudding user response:

You are updating the state in the wrong way, you are mutating the original array that is overwriting the exiting array, Instead, you need to do it in an immutable way that is providing a new Instance of diary whenever you want to update it, you can do in the following way

  useEffect(() => {
  if (hit) {
    const diaryCopy = diary.map((d, ind) => {
       if (ind === index)  {
           // The Diary ingredient you want to update
           d.ingredient = {
             productName: hit.productName,
             nutrients: {
              "energy-kcal_serving": hit.calories,
              protein_serving: hit.protein,
              carbohydrates_serving: hit.carbs,
              fat_serving: hit.fats,
            }
         };
       } 
       return d;
   } );
    
    setDiary(diaryCopy);
  }
}, [hit, selectedHit]);
  • Related