DEV Community

Mike Talbot ⭐
Mike Talbot ⭐

Posted on

3 2

Async components in React - Open Source library

Open Source project on GitHub

I've been working with Hooks in React for a while, but still kept stumbling over writing good async code that would render what it could, when it could. This is especially tricky if you have lots of "non-fetch" based api calls.

We have an async API that uses local IndexedDb and online resources if they are available to be optimal offline. This pretty much rules out Suspense for now.

We've built our own component library that might be useful to others. It lets you compose components the way you'd expect. The simplest example being to just call a few async calls and then render the result:

const useStyles = makeStyles(theme=>{
    return {
        icon: {
            backgroundColor: theme.palette.primary.main
        }
    }
})

export const ExampleComponent1 = createAsyncComponent(function Weather({
    lat,
    lon
}) {
    const classes = useStyles()
    return async ()=> {
        const response = await fetch(
            `https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&units=metric&appid=${API_KEY}`
        )
        const data = await response.json()
        return <List>
            <ListItem>
                <ListItemText primary={data.current.weather[0].main} secondary={data.timezone}/>
            </ListItem>
            <ListItem>
                <ListItemAvatar>
                    <Avatar className={classes.icon}>
                        <FaThermometerFull/>
                    </Avatar>
                </ListItemAvatar>
                <ListItemText primary={`${data.current.temp} C`} secondary={"Temperature"}/>
            </ListItem>
            <ListItem>
                <ListItemAvatar>
                    <Avatar className={classes.icon}>
                        <GiWaterDrop/>
                    </Avatar>
                </ListItemAvatar>
                <ListItemText primary={`${data.current.humidity}%`} secondary={"Humidity"}/>
            </ListItem>
        </List>
    }
})
Enter fullscreen mode Exit fullscreen mode

There are some good working examples in the example project on the Github repo and a demo of them here.

It composes like a regular React component but allows for async and the usual kind of fallbacks for loaders etc. It also ensures you can call useful hooks like styles and contexts before you get into the async guts.

It goes further though, allowing for progress reporting and out of sequence rendering:

export const ExampleComponent3 = createAsyncComponent(
    async function MyComponent({ resolve }) {
        const order = [10, 7, 4, 1, 2, 8, 6, 9, 3, 5]
        for (let i = 0; i < 10; i++) {
            let item = order[i]
            resolve(
                item,
                <Box p={1}>
                    I am item index {item} - rendered in sequence {i + 1}
                </Box>
            )

            if (i < 9) {
                resolve(order[i + 1], <Box ml={1}><CircularProgress color={"secondary"} size={20}/></Box>)
            }
            await new Promise((resolve) => setTimeout(resolve, 1500))
        }
    }
)
Enter fullscreen mode Exit fullscreen mode

MIT licensed - available on npm

npm install --save react-async-component-hoc
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

Simplify data collection in your JS app with a fully integrated form management platform. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more. Integrates with any backend system, giving you full control over your data and no user limits.

Learn more

Top comments (3)

Collapse
 
mbrtn profile image
Ruslan Shashkov

What is createAsyncComponent here?

Collapse
 
miketalbot profile image
Mike Talbot ⭐

The library we have written. Available on MIT license from the link.

Collapse
 
mbrtn profile image
Ruslan Shashkov

Will check it out, thanx!

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️