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.
-
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