Home > Software design >  Array of components gets reinitialized on every state change
Array of components gets reinitialized on every state change

Time:06-14

I'm developing a form for creating training programs and to show a week, I first create an array of all the days. What day gets rendered depends on the current day (state). The problem is that every time I change the current day, i.e. click another day-tab, the array seems to be reinitialized (I put a console.log for each day in the array, as can be seen in the code).

I really hope to find a solution which creates all days, and then simply picks one from the array without creating the array all over again each time one day is accessed.

Do you have any suggestions?

I've tried (among other things): refactoring out components (before, there were no "WeekView", "DayView"), useMemo-hook.

Source:

import React, { useContext } from 'react';
import { ProgramContext } from '../state/context';
import { setCurrentDay } from '../state/reducer';
import { Tabs, TabWindow, WindowTab } from '../styled';
import DayView from './DayView';

const WeekView: React.FC = () => {
  const { state, dispatch } = useContext(ProgramContext);

  const handleDayClick = (index: number) => () => {
    if (index === state.currentDay) return;
    dispatch(setCurrentDay(index));
  };

  const days = [...Array(state.daysPerWeek).keys()]
    .map(i => i   state.currentWeek * state.daysPerWeek)
    .map(day => {
      console.log(day);
      return (
        <DayView key={day} day={day} />
      )
    });

  return (
    <TabWindow>
      <Tabs>
        {[...Array(state.daysPerWeek).keys()].map(day => {
          return (
            <WindowTab
              active={state.currentDay === day}
              key={day}
              onClick={handleDayClick(day)}
            >
              {`Dag ${(day % state.daysPerWeek)   1}`}
            </WindowTab>
          )
        })}
      </Tabs>
      {days[state.currentDay]}
    </TabWindow>
  )
};

export default WeekView;

CodePudding user response:

Your problem is you initialize days for every re-rendering of that component.

For a potential fix, you should add another state for days, and only update days when state.currentWeek or state.daysPerWeek gets changed.

import React, { useContext, useEffect, useState } from 'react';
import { ProgramContext } from '../state/context';
import { setCurrentDay } from '../state/reducer';
import { Tabs, TabWindow, WindowTab } from '../styled';
import DayView from './DayView';

const WeekView: React.FC = () => {
  const [days, setDays] = useState([]);
  const { state, dispatch } = useContext(ProgramContext);

  const handleDayClick = (index: number) => () => {
    if (index === state.currentDay) return;
    dispatch(setCurrentDay(index));
  };

  useEffect(() => {
    const updatedDays = [...Array(state.daysPerWeek).keys()]
    .map(i => i   state.currentWeek * state.daysPerWeek)
    .map(day => {
      console.log(day);
      return (
        <DayView key={day} day={day} />
      )
    });
    setDays(updatedDays)
  }, [state.currentWeek, state.daysPerWeek])

  return (
    <TabWindow>
      <Tabs>
        {[...Array(state.daysPerWeek).keys()].map(day => {
          return (
            <WindowTab
              active={state.currentDay === day}
              key={day}
              onClick={handleDayClick(day)}
            >
              {`Dag ${(day % state.daysPerWeek)   1}`}
            </WindowTab>
          )
        })}
      </Tabs>
      {days.length && days[state.currentDay]}
    </TabWindow>
  )
};

export default WeekView;
  • Related