I followed the Apollo documentation to provide two mutations (createUser then signInUser) on a single React component, but one mutation (the "outer" one - signInUser) is not accessible to my code (this.props.signInUser is not a function). Maybe my server-side-enabled setup is masking one mutation, but I don't see where. Help appreciated :)
See full code here.
EDIT: same issue when using compose, see code.
You just need to name the mutations when passing them into the component, otherwise they are ALL called mutate, and override one another.
(By using the props function)
Here's a full example with named mutations:
https://gist.github.com/Siyfion/a2e9626ed431f8ff91af2c9b8cba1d67
It was caused by my apollo higher-order component which did more complex things than just calling Apollo's graphql (related to server-side rendering) and somehow must be masking properties. I bypassed this SSR behaviour for these mutations (not needed), see code.
Related
I have an Object of data that I store as my context. It gets filled with API responses and I feel like performance-wise I'm doing something wrong.
I tried to look into ImmutableJS but there is no reference of combining ImmutableJS with ContextAPI. Is combining them together doesn't give any benefits? And if it does do have an example of to how develop such a thing?
Whether you use context directly, add redux or pass down props through your component makes no difference to how you use immutable. ImmutableJS simply makes sure that an object does not change unintentionally and that it can be checked for changes with fast reference equality.
The problem you describe could arise from the fact that your context object changes whenever any response data is modified. Therefore it would trigger a rerender on all context consumers (see caveats). I like Immutable and use it in a large project, but if I am correct, it won't make a difference, you would have to fix the root cause or handle changes with shouldComponentUpdate.
I suggest you look into redux (or some other context provider) or show us code.
Don’t try solving your problem by introducing a dependency. It won’t be a magic bullet.
From what you describe, your context object changes frequently and is causing your component tree to rerender too often.
Maybe try creating multiple contexts that are only relevant for parts of the app. That way rerenders will only happen with subtrees using specific context.
I have a UserContext and a SocketContext (socket.io) that need to be access by multiple components. Some of these components need to use both of these contexts and force me to use the Consumer and pass values in as props instead of using contextType.
Is it good practice to create a GlobalContext that contains both the user and socket object? I have looked into React hooks which have useContext. Should I use this instead?
In general, it is good idea to keep contexts apart. When context is changed, components which consume it will be probably re-render. If you're going to use useContext hook, there are 3 recommended solutions on how to keep components from frequent updates when context changes. First solution suggests to split contexts.
Even if you will not use useContext, frequent re-rendering may become problem with single context. So it is possible to consume multiple context.
And suggested solution for several context values, changing together.
If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.
I'm building a GraphQL app, and all is mostly making sense so far. I've now gotten to the point where I want a modal component to delete an element.
In previous Redux apps I've made an action creator that takes in the operation, object type and the object, e.g:
this.props.openModal('delete','task',taskObject)
...however with GraphQL you need to specify exactly what schema type any mutation is expecting. Is this approach still possible? Or do I need to make a different modal mutation definition for every single object type in the app?
I guess converting it to a JSON string might do, but feels messy. So far GraphQL just seems like tons and tons of repetition, and I'm trying to keep that to a minimum, y'know?
Whelp, never mind. Apollo doesn't type-check #client mutations, so it's a non-issue for now.
I'm working on a part of a React app in which a high-level component creates and passes certain props down through a few layers of components that don't use them to a final component that does.
When validating props with propTypes, is there a good reason to list these props to be checked at every level, going down through the layers? Or is it acceptable to check them only in the final component that uses them?
It seems to me that the former method is redundant; the latter seems to make more sense to me, but I'm curious if there is a reason why I ought to do the former. I haven't seen any discussion on it, which could mean it's an unimportant question, but I'd be interested to know.
I agree with you about if you use props only for dril down for children in the tree, it can be done only once at the leaf components, where you realy use this data. I recently find out that one more place is important for props validation: the components which fetch data from out of app scope, such as backend, because sometimes the structure of the data changes or the data types, then it will be dificult to find which part is broken without props validation.
I'm using Apollo Client and React and I'm looking for a strategy to keep my component and component data requirements colocated in such a way that it can be accessible to parent/sibling/child components that might need it for queries and mutations. I want to be able to easily update the data requirements which in turn will update the fields that are queried by some parent component or returned by a mutation in a parent/sibling/child in order to accurately update my Apollo cache.
I have tried creating a global high level graphql directory where all my queries/mutations.graphql files are located, importing all the related fragment files located throughout my app, and then importing those directly, but this can get tedious and doesn't follow the parent/child theme where parent queries include children fragments. Also in large projects you end up traversing long file paths when importing.
I have also tried just creating fragment files colocated in the global graphql directory that correspond to component files but this doesn't give me the "component/data requirement" colocation I'm looking for.
This works:
class CommentListItem extends Component {
static fragments = {
comment: gql`
#...
`,
}
}
class CommentList extends Component {
static fragments = {
comment: gql`
#...
${CommentListItem.fragments.comment}
`,
}
}
class CommentsPage extends Component {
static fragments = {
comment: gql`
#...
${CommentList.fragments.comment}
`,
}
}
graphql(gql`
query Comments {
comments {
...CommentsListItemComment
}
}
${CommentsPage.fragments.comment}
`)
However, if I want a mutation in a descendent of CommentsPage I can't reference the fragment composition from CommentsPage.fragments.comment.
Is there a preferred method or best practice for this type of thing?
Structuring Queries
How to structure your code is always a matter of a personal taste but I think the collocation of queries and components is a big strength of GraphQL.
For queries I took a lot of inspiration from Relay Modern and the solution looks very close to what you described in the code. Right now as the project becomes bigger and we want to generate Flow type definitions for our queries, putting them into separate files next to the component files is also an option. This will be very similar to CSS-modules.
Structuring Mutations
When it comes to mutations it often gets much harder to find a good place for them. Mutations need to be called on events far down the component tree and often change the state of the application in multiple states of the app. In this case you want the caller to be unaware of the data consumers. Using fragments might seem like an easy answer. The mutation would just include all fragments that are defined for a specific type. While the mutation now does not need to know which fields are required it needs to know who requires fields on the type. I want to point out two slightly different approaches that you can use to base your design on.
Global Mutations: The Relay Approach
In Relay Modern Mutations are basically global operations, that can be triggered by any component. This approach is not to bad since most mutations are only written once and thanks to variables are very reusable. They operate on one global state and don't care about which UI part consumes the update. When defining a mutation result you should usually query the properties that might have changed by the mutation instead of all the properties that are required by other components (through fragments). E.g. the mutation likeComment(id: ID!) should probably query for the likeCount and likes field on comment and not care much if any component uses the field at all or what other fields components require on Comment. This approach gets a bit more difficult when you have to update other queries or fields. the mutation createComment(comment: CreateCommentInput) might want to write to the root query object's comments field. This is where Relays structure of nodes and edges comes in handy. You can learn more about Relay updates here.
# A reusable likeComment mutation
mutation likeComment($id: ID!) {
likeComment(id: $id) {
comment {
id
likeCount
likes {
id
liker {
id
name
}
}
}
}
}
Unfortunately we cannot answer one question: How far should we go? Do I need the names of the people liking the comments or does the component simply display a number of likes?
Mutations in Query Container
Not all GraphQL APIs are structured the Relay way. Furthermore Apollo binds mutations to the store similar to Redux action creators. My current approach is to have mutations on the same level as queries and then passing them down. This way you can access the children's fragments and use them in the mutations if needed. In your example the CommentListItem component might display a like button. It would define a fragment for the data dependencies, prop types according to the fragment and a function prop type likeComment: (id: string) => Promise<any>. This prop type would be passed through to the query container that wraps the CommentsPage in a query and mutation.
Summary
You can use both approaches with Apollo. A global mutations folder can contain mutations that can be used anywhere. You can then directly bind the mutations to the components that need them. One benefit is that e.g. in the likeComment example the variable id can be directly derived from the components props and does not need to be bound within the component itself. Alternatively you can pass mutations through from you query components. This gives you a broader overview of the consumers of data. In the CommentsPage it can be easier to decide what needs to be updated when a mutation completed.
Let me know what you think in the comments!