1
votes

To execute a query with Apollo you can do it the render props way or the hooks way.

https://www.apollographql.com/docs/react/data/queries/

Depending if you are using a class component or functional component.

In these examples you have to handle loading and error state, e.g.,

const { loading, error, data } = useQuery(GET_DOGS);

if (loading) return 'Loading...';
if (error) return `Error! ${error.message}`;

It feels like after a while this will get repeated, every time I want to make a query. So, I wanted to make a wrapper for it.

So, I found one post about how to do it for the component way: https://medium.com/naresh-bhatia/graphql-concepts-i-wish-someone-explained-to-me-a-year-ago-959b234ff430

But, could not find an answer for the functional way.

I tried a solution, and it works, but I don't know if it's a good solution.

So, I made a React functional component that should do the loading and error handling, and then return the data.

export function GraphQLRequest({ requestFunction, params, handleData }) {
    if (typeof requestFunction !== 'function') {
        return <ErrorAlert message={'Request function is not a function'} />
    }

    const { loading, error, data } = requestFunction(...params)

    if (loading) {
        return <div>Loading...</div> // TODO; loading spinner
    }
    if (error) {
        return <ErrorAlert message={error.message} />
    }

    handleData(data)
    return <div></div>
}

And from another component, I can put my GraphQLRequest component in the rendering part:

export function SomeView({ match: { params } }) {
    const [data, setData] = useState(null)

    const id = params.someId

    return (<div>
        <p className='title'>SomeItem {id}</p>
        <GraphQLRequest 
            handleData={data => setData(data)}
            requestFunction={getSomeInfoFromId}
            params={[id]}
        />
    </div>)
}

It works fine. But I feel a bit iffy about having an empty component that just does the fetching of data. Am I right about feeling iffy? Or should I just continue on?

1
What is the problem with the render props style? I think this is the best way of achieving what you want to do. Just because hooks work well for a lot of things does not mean that they work for all things. The thing we are really waiting for here is Suspense. Then there will probably be an even more dogmatic way of displaying loading indicators while waiting for some data fetching. Until then render props seems fine to me. - Herku

1 Answers

0
votes

You can use HOC. It plays nicely with Appollo client 3 and useQuery Hook

export const withQuery = (WrappedComponent, query) => {
  return (props) => {
    const { loading, error, data } = useQuery(query);

    if (loading) {
      return <div>Loading</div>;
    } else if (error) {
      return <div>Error</div>;
    }
    return (<WrappedComponent data={data} {...props} />)
  };
}

Usage:

const MyFunctionalComponent = ({ data }) => {
   // do something with data
};

export default withQuery(MyFunctionalComponent, myQuery);