Loading state principals
When a component displays data that is coming from an EVA service, we always have to deal with loading states, as the data could be either stale or unavailable.
Since we also use service response caching, we have two states that tell us the loading state of the service
- the response of the service (either
undefined
or the service response) - the
isLoading
state of the service state (boolean)
Loading states | response === undefined | response !== undefined |
---|---|---|
isLoading | Service is loading without previous response LoadingStateBox | Service is loading with previous response ProgressBar on Card |
!isLoading | No response Call the service | Service response is loaded Display the data |
There are two loading states that we are differentiating, and we display these states in different ways:
- when the service is loading, and there is no cached response from a previous call (the response of the service is
undefined
) - when the service is loading, and there is a cached response from a previous call (the response of the service is not
undefined
)
In code we can determine these states as follows:
import { hooks } from '@springtree/eva-sdk-react-recoil';import { useSetRequest } from '@springtreesolutions/eva-suite-react-hooks';import { exampleServiceState } from 'store/example-service';
const Example = () => { const serviceResponse = hooks.useGetServiceResponse(exampleServiceState); const serviceIsLoading = hooks.useIsServiceLoading({ serviceState: exampleServiceState, });
const serviceIsLoadingWithoutPreviousResponse = useMemo( () => serviceIsLoading && !serviceResponse, [serviceIsLoading, serviceResponse], );
const serviceIsLoadingWithPreviousResponse = useMemo( () => serviceIsLoading && serviceResponse, [serviceIsLoading, serviceResponse], );
return (/* See next section for rendering these states */);};
export default Example;
- Documentation on how to create a service state
@springtree/eva-sdk-react-recoil
: documentation, repo@springtreesolutions/eva-suite-react-hooks
: documentation, repo
#
Service loading without a current service response availableIn this case we have no previous data to display, so we display a LoadingStateBox component in a Card.
import { Card, LoadingStateBox } from '@springtree/eva-suite-ui';
// ...
const Example = () => { //... if (serviceIsLoadingWithoutPreviousResponse) { return ( <Card> <LoadingStateBox limit={3} /> </Card> ); } // ...}
#
Service loading with a current service response availableIn this case we have stale data to display from the previous service call. We display this data, and we also notify the user that new data is fetching in the background, via a ProgressBar on the Card.
import { Box, Card, ProgressBar, RelativeBox } from '@springtree/eva-suite-ui';
// ...
const Example = () => { //... return ( <Card> <RelativeBox> <ProgressBar loading={serviceIsLoadingWithPreviousResponse}> <Box> {/* Display data */} </Box> </RelativeBox> </Card> );}
// ...
#
Putting it all together/src/components/Example.tsx
import { Box, Card, ProgressBar, RelativeBox, LoadingStateBox,} from '@springtree/eva-suite-ui';import { hooks } from '@springtree/eva-sdk-react-recoil';import { useSetRequest } from '@springtreesolutions/eva-suite-react-hooks';import { exampleServiceState } from 'store/example-service';
const Example = () => { const serviceResponse = hooks.useGetServiceResponse(exampleServiceState); const serviceIsLoading = hooks.useIsServiceLoading({ serviceState: exampleServiceState, });
const serviceIsLoadingWithoutPreviousResponse = useMemo( () => serviceIsLoading && !serviceResponse, [serviceIsLoading, serviceResponse], );
const serviceIsLoadingWithPreviousResponse = useMemo( () => serviceIsLoading && serviceResponse, [serviceIsLoading, serviceResponse], );
return ( <Card> {serviceIsLoadingWithoutPreviousResponse ? ( <LoadingStateBox limit={3} /> ) : ( <RelativeBox> <ProgressBar loading={serviceIsLoadingWithPreviousResponse}> <Box> {/* Display data */} </Box> </RelativeBox> )} </Card> );};
export default Example;