-
Notifications
You must be signed in to change notification settings - Fork 6
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
refactor: try using generated react-query hooks #97
Conversation
PRO-2152 Configurable prop for UI Kit components to refetch data
We have a customer, Christian, who says
Can we have a prop for defining a refresh interval? Ideally, we will take into consideration what other libraries do. For example, Apollo Client has a react-query has react-query's |
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 1 Ignored Deployment
|
const [dataValue, setDataValue] = React.useState<string | null>() | ||
const [propsMismatch, setPropsMismatch] = React.useState(false) | ||
const [hasError, setHasError] = React.useState(false) | ||
const [isLoading, setIsLoading] = React.useState(false) | ||
|
||
const filtersString = JSON.stringify(query?.filters || []) | ||
const counterRef = React.useRef<HTMLSpanElement>(null) | ||
|
||
/** | ||
* Fetches the counter data | ||
* when the user doesn't provide | ||
* its own `value` | ||
*/ | ||
const fetchData = React.useCallback(async () => { | ||
try { | ||
setIsLoading(true) | ||
setHasError(false) | ||
|
||
const filters = JSON.parse(filtersString) | ||
|
||
const response = await request<CounterQuery, CounterQueryVariables>( | ||
PROPEL_GRAPHQL_API_ENDPOINT, | ||
CounterDocument, | ||
{ | ||
counterInput: { | ||
metricName: query?.metric, | ||
timeRange: { | ||
relative: query?.timeRange?.relative ?? null, | ||
n: query?.timeRange?.n ?? null, | ||
start: query?.timeRange?.start ?? null, | ||
stop: query?.timeRange?.stop ?? null | ||
}, | ||
filters, | ||
propeller: query?.propeller | ||
} | ||
}, | ||
{ |
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.
As best I can tell, hooks for dataValue
, hasError
, isLoading
are redundant. The useCounterQuery
, generated by the GraphQL code generator, is already handling this stuff. Additionally, I do not believe we need to stringify the filters, because @tanstack/query handles that for us.
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.
The main reason for stringifying the filters was preventing triggering the useEffect in every re-render (due to the filters array reference changing on every re-render) but yes, @tanstack/query handles that for us 😃
query?.metric, | ||
query?.accessToken, | ||
query?.timeRange?.n, | ||
query?.timeRange?.relative, | ||
query?.timeRange?.start, | ||
query?.timeRange?.stop, | ||
query?.propeller, | ||
filtersString |
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 believe @tanstack/query is tracking these dependencies for us.
React.useEffect(() => { | ||
async function setup() { | ||
if (isStatic) { | ||
setDataValue(value) | ||
} | ||
|
||
if (!isStatic) { | ||
const fetchedValue = await fetchData() | ||
|
||
if (fetchedValue === undefined) { | ||
setHasError(true) | ||
// console.error(`QueryError: Your metric ${query?.metric} returned undefined.`) we will set logs as a feature later | ||
return | ||
} | ||
|
||
setDataValue(fetchedValue) | ||
} | ||
} | ||
|
||
setup() | ||
}, [fetchData, isStatic, query?.metric, value]) |
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 pretty sure this is not necessary. Again, this is functionality @tanstack/react-query provides us.
|
||
const handlers = [ | ||
graphql.query('Counter', (req, res, ctx) => { | ||
mockCounterQuery((req, res, ctx) => { |
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 believe we should be using the GraphQL code generator provided mock handlers. They give the best type safety.
@@ -53,4 +53,6 @@ describe('TimeSeries', () => { | |||
expect(chartLabels).toEqual(timeSeries.labels) | |||
expect(chartData).toEqual(timeSeries.values) | |||
}) | |||
|
|||
// TODO: Add error tests. |
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.
We should also have error tests for the Leaderboard.
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.
LGTM, I'm just going to add the test button I added in the other PR, add the error tests we are missing and fix a small issue with the static mode loading state.
}, | ||
{ | ||
const { | ||
isInitialLoading: isLoadingQuery, |
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.
Here I changed to isInitialLoading
because isLoading
will always be true
when the query is disabled, this is an intended behavior from react-query that means there is no data yet. To address this kind of cases they added isInitialLoading
which is a derived flag from isLoading && isFetching
so it should work for us.
https://tanstack.com/query/v4/docs/react/guides/disabling-queries#isinitialloading
React.useEffect(() => { | ||
try { | ||
if (variant !== 'bar' && variant !== 'table') { | ||
// console.error('InvalidPropsError: `variant` prop must be either `bar` or `table`') we will set logs as a feature later | ||
throw new Error('InvalidPropsError') | ||
} | ||
setPropsMismatch(false) | ||
} catch { | ||
setPropsMismatch(true) | ||
} | ||
}, [variant]) | ||
|
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.
This was causing a bug, when there was a props mismatch error such as the user not passing rows but passing header for example, if the variant was correct this was setting the props mismatch error to false
anyways, overriding the true
value from handlePropsMismatch
. To fix it, I moved this to the handlePropsMismatch
function.
I manually tested. It LGTM. But we need to make manual testing easier 🤔 |
Description
@felipecadavid I think we need to take a simpler approach to using react-query. The GraphQL code generator is already producing react-query hooks, so we should not be writing more code to wrap react-query or to use features like
refetchInterval
. And actually, we don't even need to depend on graphql-request, we can usefetch
.Let's please try to get a version of this working, with your React 16, 17 and 18 app changes.
It's not yet working, and I'm not sure why.There's a lot of complicated hook logic in the components that should be simplified.UPDATE: I got it working. Additionally, I noticed
isStatic
. So it becomes(isStatic && loading) || (!isStatic && isLoading)
. It's not super clean. We should come back and simplify this.Checklist
Before merging to main:
Release notes