React call helper function in loop page crashes

I am trying to use a helper function getVitalsFromObs to loop through an array. The reason why i created the helper function was to minimize code and reuse the function somewhere else. My page loads perfectly at first, but after several seconds, i get this error :

Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
Warning: Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. You can only call Hooks at the top level of your React function.

My helper function looks like this :

export const getVitalsFromObs = (enc) => {
  const config = useConfig() as ConfigObject;

  const vitals: Array<PatientVitals> = [];

  enc.obs?.forEach((obs: Observation) => {
    if (obs.concept?.uuid === config.concepts.pulseUuid) {
      vitals.push({
        pulse: obs.value,
        provider: {
          name: enc.encounterProviders.length ? enc.encounterProviders[0].provider.person.display : '',
          role: enc.encounterProviders.length ? enc.encounterProviders[0].encounterRole.display : '',
        },
        time: formatTime(parseDate(obs.obsDatetime)),
      });
    } else if (obs.concept?.uuid === config.concepts.oxygenSaturationUuid) {
      vitals.push({
        oxygenSaturation: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.respiratoryRateUuid) {
      vitals.push({
        respiratoryRate: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.temperatureUuid) {
      vitals.push({
        temperature: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.systolicBloodPressureUuid) {
      vitals.push({
        systolic: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.diastolicBloodPressureUuid) {
      vitals.push({
        diastolic: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.weightUuid) {
      vitals.push({
        weight: obs.value,
      });
    } else if (obs.concept?.uuid === config.concepts.heightUuid) {
      vitals.push({
        height: obs.value,
      });
    }
  });
  return [vitals];
};

And my view looks like this :

import { getVitalsFromObs } from '../../helpers/vitals-helper';

const PastVisitSummary: React.FC<PastVisitSummaryProps> = ({ encounters, patientUuid }) => {
    const [x, setX] = useState([]);

    encounters?.forEach((encounter) => {
        encounter?.encounters?.forEach((val: Encounter) => {
            setX(getVitalsFromObs(val));
        }),
    }, [encounters]);

    return (
        <div className={styles.wrapper}>
            <Tabs className={`${styles.verticalTabs} ${isTablet ? styles.tabletTabs : styles.desktopTabs}`}>
              <Tab
                className={`${styles.tab} ${styles.bodyLong01} ${selectedTabIndex === 0 && styles.selectedTab}`}
                id="vitals-tab"
                onClick={() => setSelectedTabIndex(0)}
                label={t('vitals', 'Vitals')}>
                <Vitals vitals={x} />
              </Tab>
            </Tabs>
        </div> 
    )         
}

I have also tried using useEffect hook like this

useEffect(() => {
    encounters?.forEach((encounter) => {
      encounter?.encounters?.forEach((val: Encounter) => {
        setX(getVitalsFromObs(val));
      });
    });
}, [encounters]);

but i get this error openmrs-esm-form-entry-app.js:1 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component . Any advise or recommendations on what i might be doing wrong will be highly appreciated.

encounters?.forEach((encounter) => {
    encounter?.encounters?.forEach((val: Encounter) => {
        setX(getVitalsFromObs(val));
    }),
}, [encounters]);

Why are you passing [encounters] as the thisArg to the forEach callback? Also, with an arrow function as the callback this is lexical.

Note: If passing the callback function used an arrow function expression, the thisArg parameter could be omitted, since all arrow functions lexically bind the this value.

That looks more like a leftover from a useEffect or something.


Do you have a repo you can post?

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.