ambe5960
ambe5960

Reputation: 2000

Typescript fetch data from server and loading state

I am pretty new to typescript and am not sure how to best go about this rather common scenario. I fetch data and pass it into a template component as such:

const ProfilePage: FC = (): JSX.Element => {
  const { data, isDataLoading } = useProfileData();

  return (
    <ProfileTemplate
      data={!isDataLoading && data}
    />
  );
};

This is the ProfileTemplate component

import { profile_data, Maybe } from '../api-client';

type ProfileProps = {
  data: Maybe<profile_data>;
}

export const ProfileTemplate: FC<ProfileProps> = ({ data }): JSX.Element => {
  ...
  <StaticField label="First Name" text={data.first_name} />
  <StaticField label="Last Name" text={data.last_name} />
  ...
}

Calling it as such results in Type 'false | Maybe<profile>' is not assignable to type 'Maybe<profile>'. I can remove the conditional which checks isDataLoading first, however I then get object is possibly null errors in my <StaticField> components.

first_name and last_name can be null or empty in the database. Although I realize that's not what's causing the object is possibly null errors, rather an empty profile_data object, when no data has been returned from the server yet.

How should I best handle this situation?

My `<StaticField>` component looks like so: interface Props {
  label: string;
  text?: Maybe<string>;
}

export const StaticField: FunctionComponent<Props> = ({ label, text }): JSX.Element => {
  return (
    <Box>
      <Text color="gray.BlackCoral" className={classes.label}>
        {label}
      </Text>
      <Text>{text}</Text>
    </Box>
  );
};

Upvotes: 0

Views: 1081

Answers (3)

maazadeeb
maazadeeb

Reputation: 6112

If I understand it correctly, Maybe seems to have been defined like type Maybe<T> = T | null.

So, since you expect data to be either present or null, you can change your consumption logic to

<ProfileTemplate
  data={isDataLoading ? null : data}
/>

This will get rid of the error 'false | Maybe<profile>' is not assignable to type 'Maybe<profile>'.. This error shows up because in your existing code !isDataLoading && data can either evaluate to false or whatever the type of data is.

Secondly, since data can be null, using it to access data.first_name can be a problem. That's what TypeScript is trying to tell you. One way to "fix" it would be to use the optional chaining data?.first_name to tell the compiler that you'll access first_name iff data is defined.

Upvotes: 0

Daniel Duong
Daniel Duong

Reputation: 1104

This line here is the problem

  data={!isDataLoading && data}

I suggest you refactor your code to have conditional render like so

if (isDataLoading || !data) {
    return null
}
return (
    <ProfileTemplate data={data}/>
);

However you can simply replace the data prop with a ternary It is always good practice to extract into constants

const data = isDataLoading ? data : undefined;
return (
    <ProfileTemplate data={data}/>
);

The second option still does not account for what should be rendered when you have data undefined So you would need a render of null inside ProfileTemplate

Upvotes: 1

Viet
Viet

Reputation: 12787

You should handle like this to make sure ProfileTemplate always has data

{
  !isDataLoading && <ProfileTemplate data={data} />;
}

Upvotes: 1

Related Questions