setting state inside useEffect

Viewed 91

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 };
};
1 Answers

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 };
};
Related