Glory Raj
Glory Raj

Reputation: 17701

setting state inside useEffect

I am trying to update the state (tableColumnConfiguration) inside useEffect and then pass on that state to the child component, but this code throws a "Maximum update depth exceeded" error and the app freezes without being able to click anything on screen.

const[environmentTableColumns, setEnvironmentTableCoulmns] = useState(environmentConditionsColumns);

const {
  data: conditionTypeData,
  loading: loadingConditionTypeData,
  errorRedirect: conditionTypeDataErrorRedirect
} = useSectionEnumQuery('conditionType'); // this is API call


useEffect(() => {
  if (conditionTypeData) {
    let data; 
    let updatedEnvironmentColumnConfiguration = environmentConditionsColumns;
    updatedEnvironmentColumnConfiguration = updatedEnvironmentColumnConfiguration.map(item => {
      if (item.dataIndex === 'conditionType') {
        data = conditionTypeData;
      }
      return data
        ? {
          ...item,
          render: text => {
            return renderEnum(text, data);
          }
        }
        : item;
    });
    setEnvironmentTableCoulmns(updatedEnvironmentColumnConfiguration); // here i am setting the state 
  }
}, [conditionTypeData])

Child component :

<SpaceTypeTable
  values={values}
  isReadOnly={isReadOnly}
  isProjectSystem={isProjectSystem}
  tableTitle="Environment Criteria"
  mappedLibrarySourceArray="environments"
  sourceRender={p => renderGuidelineItem(p, true)}
  tableColumns={environmentTableColumns} // here i am passing the column configuration
  section={MASTER_SECTIONS.LIBRARY_ENVIRONMENT}
  guidelines={guidelines}
  form={form}
  handleWarning={handleWarning}
/>

What's causing this useEffect loop?

Update : UseSectionEnumQuery :

export const useSectionEnumQuery = resultFieldName => {
  const { data: result, loading, error } = useQuery(ENUM_TYPES(resultFieldName));
  const data = result?.[resultFieldName] && sortBy(result[resultFieldName], o => o.label);
  const errorRedirect = error && errorRedirectElement(error, resultFieldName);
  return { loading, data, errorRedirect };
};

Upvotes: 4

Views: 123

Answers (1)

Todd Skelton
Todd Skelton

Reputation: 7239

This line is causing your problem.

const data = result?.[resultFieldName] && sortBy(result[resultFieldName], o => o.label);

data will be a new reference each render and it's going to trigger your useEffect every render because data is conditionTypeData and it's in your dependencies.

Can you try memoizing the value, so it only changes when result changes.

export const useSectionEnumQuery = resultFieldName => {
  const { data: result, loading, error } = useQuery(ENUM_TYPES(resultFieldName));
  const data = useMemo(() => result?.[resultFieldName] && sortBy(result[resultFieldName], o => o.label), [result, resultFieldName]);
  const errorRedirect = useMemo(() => error && errorRedirectElement(error, resultFieldName), [error, resultFieldName]);
  return { loading, data, errorRedirect };
};

Upvotes: 2

Related Questions