Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render async component in React Router v4

I want to render a component based on the payload it receives from an api like below

<Route path="/foo/bar" render={() => {
  return (get('/some/api').then((res) => {
    return <Baz data={res.data} />
          }).catch((err) => console.log))
        }} />

But I'm getting the error:

Objects are not valid as a React child (found: [object Promise]). If you 
meant to render a collection of children, use an array instead. 

even when I do wrap Baz in []

like image 566
stackjlei Avatar asked Dec 18 '17 23:12

stackjlei


People also ask

Can render in react be async?

With Suspense, you have the ability to suspend component rendering while async data is being loaded. You can pause any state update until the data is ready, and you can add async loading to any component deep in the tree without plumbing all the props and state through your app and hoisting the logic.

Is react Router async?

Async-react-router is react router that can easily get initial props using async/await or promise. If you use this library, You can get the initial props like Next. js. And this library works only on client also.

What are the components of react Router v4?

The 'react-router' library is now split into three separate packages. react-router-dom: Designed for web applications. react-router-native: Designed for mobile applications. react-router-core: Can be used anywhere for core applications.

Can you make react components async?

Async component is the classic interface of React Async, and we can use it to make React components more declarative. Here, we can directly use the <Async> component in JSX to apply the render props pattern. Following is a simple example of using <Async> component to fetch data.


1 Answers

unfortunately with the latest version of React - 16. Async rendering is not an option yet.

With React Router v4, the render props of Route component expects a valid React Element or array of React Elements to be returned, therefore, it doesn't accept the Promise object return from your function.

However, it's not impossible to achieve what you want with the current version of React and React Router. You just need to tweak your code a little bit. Instead of returning a Promise, your render should return a React Component, then you can do conditional rendering based on async value inside that component.

It should look like:

<Route path="/foo/bar" render={BazWrapper} />


class BazWrapper extends React.Component {

    // Do asynchronous action here
    async componentDidMount() {
       try {
          const apiValue = await get('/some/api');
          this.setState({ apiValue })
       } catch(err) {
          // error handling
       }
    }

    render() {
        const { apiValue } = this.state; 
        return <Baz data={apiValue} />;
    }

}

By calling setState after the asynchronous call finish, you let React Component know that the data is ready and it's should re-render the component.

like image 88
Thai Duong Tran Avatar answered Sep 21 '22 04:09

Thai Duong Tran