Accessing Fragment data within array, in intermediate component #8859
Replies: 7 comments 10 replies
-
Did you figure this out? I'm having the same issue, the generated type is giving an in-between $fragmentRefs field |
Beta Was this translation helpful? Give feedback.
-
Without the https://the-guild.dev/graphql/codegen/plugins/presets/gql-tag-operations-preset#fragment-masking Setup the import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'src/path/to/your/schema.graphql',
documents: ['src/**/*.ts', '!src/gql/**/*'],
generates: {
'./src/gql/': {
preset: 'gql-tag-operations-preset'
}
}
}
export default config import { gql, DocumentType } from '../gql'
const TweetFragment = gql(/* GraphQL */ `
fragment TweetFragment on Tweet {
id
body
}
`)
const Tweet = (props: {
// NOTE: We do not use useFragment anymore and we do not use FragmentType but DocumentType instead
tweet: DocumentType<typeof TweetFragment>
}) => {
return <li data-id={props.tweet.id}>{props.tweet.body}</li>
}
const TweetsQuery = gql(/* GraphQL */ `
query TweetsQuery {
Tweets {
id
...TweetFragment
}
}
`)
const Tweets = () => {
const [result] = useQuery({ query: TweetsQuery })
const { data, fetching, error } = result
if (fetching) return <p>Loading…</p>
if (error) return <p>Oh no… {error.message}</p>
// NOTE: here the Tweets object will not come with that weird $fragmentRefs
return (
<ul>
{data.Tweets.map(tweet => (
<Tweet key={tweet.id} tweet={tweet} />
))}
</ul>
)
} with previous steps you can solve the problems:
|
Beta Was this translation helpful? Give feedback.
-
Leaving this here in case it helps anyone. The query export const aDocument = graphql(/* GraphQL */ `
query A {
anOperation() {
anObject {
items {
...Item
}
}
}
}
`); The component which declares it's data dependencies export const ItemFragment = graphql(/* GraphQL */ `
fragment Item on Items {
aField
}
`);
interface Props {
items: FragmentType<typeof ItemFragmentDoc>[]; // notice the use of `[]`
}
export default function Items(props: Props) {
// I use getFragmentData instead of useFragment here
const items = getFragmentData(ItemFragmentDoc, props.items);
} The component which invokes the query const { data } = useQuery(aDocument);
const items = data?.anOperation.anObject?.items ?? [];
<SomeComponent items={items} /> |
Beta Was this translation helpful? Give feedback.
-
Any recommendations on how to solve this if you're defining all your queries and fragments in |
Beta Was this translation helpful? Give feedback.
-
Having the same issue. query {
items {
id
subItems {
...SubItemFields
}
}
}
fragment SubItemFields on SubItem {
id
} You cannot do this from the items.map(item => item.subItems.map(subItem => subItem.id)) subItem will only have __typename, not id. |
Beta Was this translation helpful? Give feedback.
-
Running into the same issue here with intermediate components. It doesn't look like any of the answers have given a solution. I've been trying to figure out the proper terminology to see if I can google anything, but coming across this discussion and seeing the troubles people have run into, I'm not sure there is one? While @jmayergit solution is good for a single level, what happens when you need to pass masked data down through multiple components? For example, we have // Top level component
const AnObject = graphql(`
fragment AnObject on Object {
id
items {
id
...Item
}
otherItems {
...OtherItem
}
}
`);
export const aDocument = graphql(/* GraphQL */ `
query A {
anOperation() {
anObject {
...AnObject
}
}
}
`);
export default function TopLevel() {
const { data } = useQuery(A});
const anObject = data?.anObject
if (!anObject) return null;
const unmaskedObject = getFragmentData(AnObject, anObject);
return (
<>
{unmaskedObject.items.map(item => <Item id={item.id} item={item} otherItems={unmaskedObject.otherItems} />)}
</>
)
} Now we go into const Item = graphql(`
fragment Item on Item {
id
name
}
`);
type Props = {
item: FragmentType<typeof Item>;
otherItems: ???
}
export default function Item(props: Props) {
const item = getFragmentData(Item, props.item);
return (
<>
<p>{item.name}</p>
<OtherItems otherItems={props.otherItems} />
</>
)
} And const OtherItem = graphql(`
fragment OtherItem on OtherItem {
id
name
}
`);
type Props = {
otherItems: FragmentType<typeof OtherItem>[];
}
export default function OtherItem(props: Props) {
const otherItems = getFragmentData(OtherItem, props.otherItems);
return (
<>
{otherItems.map(otherItem => (<p id={otherItem.id}>{otherItem.name}</p>))
</>
)
} I'm unsure of what to do in the What I tried to do was create an intermediate fragment, say If we update the props in type Props = {
item: FragmentType<typeof Item>;
otherItems: FragmentType<typeof Item_OtherItem>[]
} and add the This approach seems to not work unless there was some union type of @Urigo Are there any docs or information out there on what to do in a situation like this? |
Beta Was this translation helpful? Give feedback.
-
I ran into the same issue, This did not solve my issue :( |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
I'm having trouble correctly typing the data in a Typescript React component when using a Fragment - with the code generator's client-preset.
I have a parent component that performs a query:
Parent component
The query includes use of a fragment and returns an array of 'projects' within data.
The project array is then passed into a
<ProjectGrid>
component which renders multiple<ProjectItem>
s, passing in a single project from the projects array.<ProjectGrid>
also needs to access the projects data.<ProjectGrid>
<ProjectItem>
Question
I have attempted to type it as so:
Which is an Array of Objects type, however the Fragment's fields do not exist within the objects, resulting in this linting error when trying to access:
Dependencies
Beta Was this translation helpful? Give feedback.
All reactions