My goal is to update and display new data for {data.contact.contactInformation}
automatically, once I click the button for the updateMutation
. However, it only works once I refresh the page. From my understanding, the IDs must be returned and then Apollo should handle the rest, according to the Apollo data mutation docs.
But I seem to have some mistake in my code. Do you see what's wrong with it?
const FEED_QUERY = gql`
query Contact($id: Int!) {
contact(id: $id) {
id
contactInformation
belongsTo {
id
username
email
}
}
}
`;
const UPDATE_CONTACT_DETAILS = gql`
mutation updateContactDetails($contactInformation: String!) {
updateContactDetails(contactInformation: $contactInformation) {
id
contactInformation
belongsTo {
id
username
email
}
}
}
`;
function EmergencyContact() {
const params = useParams();
const { loading, error, data } = useQuery(FEED_QUERY, {
variables: { id: params.contactId }
});
const [updateContactDetails] = useMutation(UPDATE_CONTACT_DETAILS);
const [value, setValue] = useState("");
if (loading) return "Loading...";
if (error) return `Error! ${error.message}`;
return (
<>
<div key={data.contact.id}>
{data.contact.contactInformation}
<form
onSubmit={e => {
e.preventDefault();
updateContactDetails({
variables: {
contactInformation: value
}
});
setValue("");
}}
>
<input value={value} onChange={e => setValue(e.target.value)} />
<button type="submit">Update Contact Information</button>
</form>
</div>
</>
);
}
export default EmergencyContact;
schema.py
class ContactInformationType(DjangoObjectType):
class Meta:
model = ContactInformation
class Query(graphene.ObjectType):
contact = graphene.Field(ContactInformationType, id=graphene.Int())
contact_access_key = graphene.Field(
ContactInformationType, access_key=graphene.String()
)
contact_informations = graphene.List(ContactInformationType)
@staticmethod
def resolve_contact_informations(parent, info, **kwargs):
return ContactInformation.objects.all()
@staticmethod
def resolve_contact_access_key(parent, info, **kwargs):
access_key = kwargs.get("access_key")
if not access_key:
return
contact_info = ContactInformation.objects.filter(access_key=access_key).first()
if info.context.user != contact_info.belongs_to:
raise PermissionDenied()
return contact_info
@staticmethod
@login_required
def resolve_contact(parent, info, **kwargs):
id = kwargs.get("id")
if id is not None:
contact_info = ContactInformation.objects.filter(belongs_to__pk=id).first()
if info.context.user != contact_info.belongs_to:
raise PermissionDenied()
return contact_info
class UpdateContactDetails(graphene.Mutation):
id = graphene.ID()
contact_information = graphene.String()
belongs_to = graphene.Field(UserType)
class Arguments:
contact_information = graphene.String()
@staticmethod
def mutate(self, info, contact_information):
contact_detail = ContactInformation.objects.get(belongs_to=info.context.user)
contact_detail.contact_information = contact_information
contact_detail.save()
return UpdateContactDetails(
id=contact_detail.pk,
contact_information=contact_detail.contact_information,
belongs_to=contact_detail.belongs_to,
)
class Mutation(graphene.ObjectType):
update_contact_details = UpdateContactDetails.Field()
Apollo uses both the id
and the __typename
to generate the cache key. So a User with an id
of 1
and a Post also with an id
of 1
will not share the same key -- their keys will be User:1
and Post:1
respectively. If your user
field and your updateContactDetails
return different types (even if those types have the exact same fields), they will end up with different cache keys and so Apollo will not know it needs to update the user
query. This should be fixed on the backend (i.e. make sure both fields have the same type) -- if it can't be fixed, you'll need to manually update the cache by providing an update
function to your useMutation
hook.