
от Джун Хюк Кима

GraphQL является горячим, и для этого есть уважительная причина. Короче говоря, это язык запросов, позволяющий спрашивать точно что вам нужно от вашего API. Это уменьшает ненужную передачу данных, которая может происходить с помощью различных методологий.
Я работал над проектом, где использовался сервер GraphQL. Я решил использовать React и Apollo Client в качестве моего интерфейса для связи с моим сервером GraphQL. У меня возникли определенные трудности, чтобы понять, как повторно получить запрос, а затем перенаправить мою страницу на главную страницу с обновленными данными. Вот где все стало немного труднее.
Для меня проблема заключалась в том, чтобы выяснить, как на самом деле называлась мутация и что было возвращено. Мы можем получить доступ к мутации после подключения через graphql(mutation)(*YourComponent*)
через this.props.mutate()
. Эта функция возвращает Promise. Мы можем цепочкой .then()
функции вызова функций после мутации. Функция mutate также может принимать переменные для мутации. Полный пример будет примерно таким:
this.props.mutate({ variables:{ title: this.state.title, content: this.state.content }})
Это означало бы, что наша мутация принимает две переменные, которые называются заглавием и содержимым. Они передаются в нашу мутацию, когда мы посылаем ее на наш внутренний сервер. Скажем, наша мутация – это добавление примечания с названием и содержимым. Чтобы все было понятно, я приведу простой пример того, как будет выглядеть наша мутация:
const mutation = gql` mutation AddNote($title: String, $content: String){ addNote(title:$title, content:$content){ title content } }}`
// Our component should also be connected to Apollo client, so // something like this
export default graphql(mutation)(Component)
Итак, что происходит после выполнения этой функции? Наш бэк-энд получает информацию и происходит мутация. Однако наш интерфейс не знает, что произошла мутация. Он не возвращает запрос, который мы получили ранее (в нашем случае, возможно, что-то вроде fetchAllNotes). Вот где функция мутации становится очень удобной. Мы можем передать переменную с названием refetchQueries
с помощью которого будут получены любые запросы, которые мы просим.
this.props.mutate({ variables:{ title: this.state.title, content: this.state.content }, refetchQueries:[{ query: fetchAllNotes }]}).then(() => this.props.history.push('/notes'))
В этом случае мы сообщаем клиенту Apollo повторно получить fetchAllNotesquery
после возникновения мутации. Затем перенаправить пользователя на /notes
каталог (React-Router). Помните, что наша функция mutate возвращает Promise? Все это должно работать, не правда ли? Ну… по задумке, команда Apollo так и сделала refetchQueries
случилось бы в это же время как .then
заявление. Это означает, что оператор .then может встречаться раньше refetchQueries
. Это может привести к тому, что компонент, которому требуется обновленная информация, не будет обновляться.
В этом конкретном случае наш пользователь будет перенаправлен раньше в refetchQueries
происходит. Информация не будет обновляться. Это сложно, поскольку функция mutate возвращает Promise. Команда Apollo прошла мимо дизайн так что refetchQueries
может происходить рядом с любым .then
заявления. Итак, как мы справимся с этим?
Команда Apollo поняла, что это может быть проблемой. Они пришли с решением, которое разрешает refetchQueries
принять переменную, которая позволит ей вернуть Promise, и, таким образом, произойдет перед любым .then
заявления. Наш код будет выглядеть примерно так:
this.props.mutate({ variables:{ title: this.state.title, content: this.state.content }, refetchQueries:[{ query: fetchAllNotes, variables:{ awaitRefetchQueries: true } }]}).then(() => this.props.history.push('/notes'))
Если это сработало для вас, уууу! Похоже, исправление сработало! Однако лично для меня это не сработало. Кроме того, поскольку он доступен только в последних версиях Apollo Client, он не будет доступен в старых версиях Apollo Client.
Мне пришлось немного решить проблемы с жизненными циклами компонентов React, чтобы убедиться, что мой компонент будет правильно отображать обновленные данные. Именно исправление достаточно короткое и достаточно простое! На компоненте My Notes, который воспроизводит заметки и подключается к fetchAllNotes
запрос на graphql
функцию, я добавил быстрое исправление, чтобы убедиться, что мои данные правильно отображаются.
componentDidUpdate(prevProps){ if(prevProps.data.notes && prevProps.data.notes.length !== this.props.data.notes.length){ // Logic to update component with new data }}
По сути мы говорим, что когда компонент обновляется, мы хотим увидеть, был ли запрос на заметки ранее завершен (проверяя, prevProps.data.notes
существует) и если длина данных поменялась. Это позволяет нашему компоненту React обновлять информацию после завершения запроса на повторную выборку.
Теперь все должно работать! Надеюсь, awaitRefetchQueries
переменная сработала для вас и становится более известной, что является гораздо более элегантным решением. Однако найти примеры/документацию по использованию довольно трудно awaitRefetchQueries
правильно. Пока достаточно хорошего понимания жизненных циклов компонентов React, чтобы помочь вам обойти «помехи» Apollo + React!
Пожалуйста, оставляйте любые отзывы или вопросы в комментариях и я сделаю все возможное, чтобы помочь. Я ни в коем случае не эксперт, но я бы хотел вместе с вами решить проблему и помочь разобраться!