-
-
Notifications
You must be signed in to change notification settings - Fork 27
Add react query #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add react query #126
Conversation
Add query utility function using Axios. Co-authored-by: Linda Peng <linda.peng@alumni.duke.edu>
d1fb40f
to
3af872e
Compare
As we are deconstructing keys from API requests, these keys are returning as snake_cased. We should allow this instead of aliasing them as camelCased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for figuring this out, @angelocordon! Left a few comments/questions, but overall looks good!
|
||
const resourceId = matchProps.match.params.guid; | ||
// TODO: Handle Error cases | ||
const { isLoading, data } = useQuery(['resource', resourceId], getResource); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lpatmo - when the API doesn't resolve in DRF, does it return us an error object or does it throw an error? I'm curious how our getResource()
function should handle error responses? Right now we're just returning a data object:
Lines 6 to 7 in 700010a
const { data } = await axios.get(`${API_URL}/resources/${id}`); | |
return data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I should have tried this out before I made the suggestion! DRF throws a 404 error.
We could add try/catch to that function in queries.js, but if we do that the error that is returned is considered "data" and not "error".
Wondering how you feel about doing this instead:
const { isLoading, data, error } = useQuery(
['resource', resourceId],
getResource
);
const classes = useStyles();
if (error) {
console.error(error);
return <p>Sorry, there was an error!</p>;
}
if (isLoading) {
return <p>Loading...</p>;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, this then tells me that getResource
should be returning an error object from Axios then but I think that can be moved to another issue to handle errors a lot more appropriately.
|
||
const resourceId = matchProps.match.params.guid; | ||
// TODO: Handle Error cases | ||
const { isLoading, data } = useQuery(['resource', resourceId], getResource); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for figuring out this syntax for getting an individual resource ID!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not actually sure why we pass down the whole matchProps
object to the ResourcePage when only need the guid
here 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, can totally do
<Route
path="/resources/:guid"
render={matchProps => (
<ResourcePage resourceId={matchProps.match.params.guid} />
)}
/>
and
function ResourcePage({ resourceId }) {
...
ResourcePage.propTypes = {
resourceId: PropTypes.string,
};
if you want :) I don't have a preference for either.
|
||
const API_URL = '/api/v1'; | ||
|
||
const getResource = async (_key, id) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting -- this _key
is required by react query and is resources
when we call it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we don't use _key
at all here but React Query uses it to id cache responses, I believe.
The unique key you provide is used internally for refetching, caching, deduping related queries.
https://react-query.tanstack.com/docs/guides/queries#query-basics
In our case, how useQuery
works, it passes the key and a param to the callback (getResource
) so in order to get the id, I had to accommodate for the first arg useQuery
passes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it; thanks for linking to the docs!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thank you!
What type of PR is this? (check all applicable)
Context
This adds ReactQuery to replace our async fetching patterns.
Implementation Details - what was your thought process as you changed the code?
React-Query
React Query gives us a better abstraction than using React's useEffect and useState hooks. The initial discussion here was that using state to asynchronously pass data to be rendered seemed a little hacky for the following reasons:
The old way:
On mount, set state to loading and data to null, then fetch data, then reset loading state and fill in data state and then render the data state.
The new way:
Component mounts with isLoading state to be true; renders a loading component. Data is fetched, and then data is rendered.
I find this to be significantly easier to read:
Utility Functions
This PR also includes utility functions for fetching individual resources. @lpatmo and I thought it would be helpful to pull that functionality out of the component to establish utility patterns. This allows us to better isolate responsibilities and makes unit testing easier. My only concern here is that I am unsure of how the backend API will be handling errors? We are currently throwing errors (though not being handled in the UI), mainly because I think that's what Axios is supposed to be doing?
For additional resources, here are some great, short articles:
https://codeworkshop.dev/blog/2020-04-15-fetching-data-with-react-query-and-suspense/
https://www.robinwieruch.de/axios-jest
Related Tickets & Documents (Optional)
#103
#123
Added tests?
Added to documentation (readme.md or contributing.md)?