Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React child components are only half updating when switching from one to the other

I have a Home Component that contains 2 hardcoded routes and 2 mapped ones, I’m parsing the plan object to the Plan component.

<Routes>         
    <Route path='/' element={<Heading>index</Heading>}/>
    <Route path='/profile' element={<Profile />}/>
    {user && 
        user.workoutPlans.map((plan, index) => (    
            plan._id && <Route path={'/' + plan._id} key={index} element={<Plan plan={plan} />} /> 
    ))} 
</Routes> 

The Plan Component displays the plan title and contains a section where it maps an array of days to DayCards

<Heading size='2xl' mr={-3}>{plan.title}</Heading>
<Flex direction='column'>
    {plan.days.map((day, index) => (
        day._id && <DayCard planId={plan._id} day={day} key={index} />
    ))}
</Flex>

If I refresh then go to the route app.com/plan1id
I get the correct list of days [day1, day2, day3, day4, day5] + Heading: Plan1

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

If I refresh then go to the route app.com/plan2id
I get the correct list of days [other1, other2, other3] + Heading: Plan2

But if I then go from app.com/plan2id to app.com/plan1id
I get a messed up list of days [other1, other2, other3, day4, day5] + Heading: Plan1

Its the same in reverse order

But if I refresh then go to the route app.com/plan1id then got to app.com/profile
then to app.com/plan2id it works correctly returning [other1, other2, other3] + Heading: Plan2

The app state stays the same the entire time and the plan data is being parsed in correctly as far as I can tell because plan.title always displays correctly

Any ideas about why this is happing would be greatly appreciated

>Solution :

Don’t use the array index as a React key.

When switching plans the route changes, but the Plan component remains mounted and only the plan prop value updates. This triggers a rerender. But since the days are using an array index as the React key, the key doesn’t change value. Day index 2 in plan "A" is equal to day index 2 in plan "B".

You should instead use a value that is intrinsic to the data being mapped. GUIDs make for great React keys. I suggest using day._id as the React key, assuming these are unique.

<Flex direction='column'>
  {plan.days
    .filter(day => day._id)
    .map((day) => <DayCard planId={plan._id} day={day} key={day._id} />)
  }
</Flex>

May as well correct the routing code too for the Plan component.

<Routes>         
  <Route path='/' element={<Heading>index</Heading>} />
  <Route path='/profile' element={<Profile />} />
  {user?.workoutPlans
    .filter(plan => plan._id)
    .map((plan) => (
      <Route
        path={`/${plan._id}`}
        key={plan._id}
        element={<Plan plan={plan} />}
      />
    ))
  }
</Routes> 
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading