kevinydhan / gatsby-with-query Goto Github PK
View Code? Open in Web Editor NEW[WIP] A higher-order component used to decouple Gatsby's static queries
License: MIT License
[WIP] A higher-order component used to decouple Gatsby's static queries
License: MIT License
In the following type definition for WithQuery
:
import { FunctionComponent } from 'react'
type WithQuery = <Props = Record<string, never>>(
Component: FunctionComponent<Props>,
useQueryHook: () => Props
) => FunctionComponent<ReturnType<typeof useQueryHook>>
useQueryHook()
's return type should be one of the following:
props
props
In addition, the parameter for the WithQueryHOC
component should also be one of the two cases:
props
props
Considering these two requirements, a possible type definition would be to use Partial<T>
for both useQueryHook()
's return value and the parameter for the WithQueryHOC
component:
import { FunctionComponent } from 'react'
type WithQuery = <Props = Record<string, never>>(
Component: FunctionComponent<Props>,
useQueryHook: () => Partial<Props>
) => FunctionComponent<ReturnType<typeof useQueryHook>>
However, this poses the problem where calling React.createElement()
with partial props will trigger a TypeScript warning.
A possible feature would be to provide support for <StaticQuery>
. However, the immediate issue is that it seems unnecessary to utilize <StaticQuery>
as demonstrated below:
// App.tsx
import React, { FunctionComponent } from 'react'
import { graphql, StaticQuery } from 'gatsby'
import withQuery from 'gatsby-with-query'
interface AppProps {
title: string
description: string
}
export const App: FunctionComponent<AppProps> = ({ title, description }) => (
<main>
<h1>{title}</h1>
<p>{description}</p>
</main>
)
const query = graphql`
query GetSiteMetadata {
site {
siteMetadata {
title
description
}
}
}
`
// Possibly something like this?
export default withQuery<AppProps>(() => (
<StaticQuery query={query}>
{(queriedProps) => <App {...queriedProps} />}
</StaticQuery>
))
If a developer wanted to create a standalone React query hook, they will most likely have to explicitly type their hook to utilize IntelliSense for receivedProps
:
// receivedProps will be type `any`
const useGetSiteMetadataQuery = (receivedProps) => {
const queriedProps = useStaticQuery(query)
return {
...queriedProps.site.siteMetadata,
...receivedProps,
}
}
useQueryHook
import type { WithQueryHook } from 'gatsby-with-query'
import type { AppProps } from './App.d'
const useGetSiteMetadataQuery: WithQueryHook<AppProps> = (receivedProps): AppProps => {
const queriedProps = useStaticQuery(query)
return {
...queriedProps.site.siteMetadata,
...receivedProps,
}
}
receivedProps
import type { WithQueryReceivedProps } from 'gatsby-with-query'
import type { AppProps } from './App.d'
const useGetSiteMetadataQuery = (receivedProps: WithQueryReceivedProps<AppProps>): AppProps => {
const queriedProps = useStaticQuery(query)
return {
...queriedProps.site.siteMetadata,
...receivedProps,
}
}
Currently, the WithQueryHOC
component is overwriting duplicate props.<key>
:
const withQuery: WithQuery = (Component, useQueryHook) => {
const WithQueryHOC: ReturnType<WithQuery> = (receivedProps) => {
const queriedProps = useQueryHook()
return createElement(Component, {
...queriedProps,
...receivedProps, // Any duplicate keys are overwritten
})
}
// ...
}
This may or may not be a behavior that developers want. Instead, receivedProps
can be passed as an argument to useQueryHook()
and the developer can manage their component's props in the useQueryHook()
function:
// Component file
const App = () => {
// ...
}
export default withQuery<AppProps>(App, (receivedProps) => {
const queriedProps = useStaticQuery(query)
// Do some logic with received and queried props
return {
...queriedProps,
...receivedProps,
}
})
receivedProps
in their query hook?Currently, withQuery()
is a generic function. The developer has to explicitly define their prop's type definition:
export default withQuery<AppProps>(App, () => {
// ...
})
It would be nice if withQuery()
can automatically infer the type definition for the component's props
:
interface AppProps {
title: string
description: string
}
const App: FunctionComponent<AppProps> = ({ title, description }) => (
<main>
<h1>{title}</h1>
<p>{description}</p>
</main>
)
export default withQuery(App, (receivedProps) => {
// receivedProps is either a subset of AppProps or AppProps
})
I can possibly utilize Parameters<T>
to infer the component's props.
I believe it would make more sense to make react
a peer dependency. I need to figure out how to use peer dependencies.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.