Крюк Apollo useLazyQuery использует старые переменные при повторной выборке (вместо новых переменных)

#reactjs #graphql #apollo

Вопрос:

В моей базе данных хранится список элементов. Я написал запрос, чтобы случайным образом возвращать один элемент из списка при каждом нажатии кнопки. Я использую useLazyQuery и вызываю возвращаемую функцию для выполнения запроса, и она отлично работает. Я могу вызвать функцию повторной выборки при последующих нажатиях кнопок, и она правильно вернет другой случайный элемент.

Проблема возникает, когда я пытаюсь передать переменные в запрос. Я хочу предоставить различные критерии для запроса, чтобы адаптировать способ выполнения случайного выбора. Любые переменные, которые я передаю при первом вызове, повторяются при каждом повторном вызове, даже если они изменились. Я могу проследить, что они отличаются на клиенте, но распознаватель отслеживает предыдущие переменные.

 // My query
const PICK = gql`
  query Pick($options: PickOptionsInput) {
    pick(options: $options) {
      title
    }
  }
`;

// My lazy hook
const [pick, { data, refetch }] = useLazyQuery(PICK, {
    fetchPolicy: "no-cache",
  });


// My button
<MyButton
  onPick={(options) =>
     (refetch || pick)({ // Refetch unless this is the first click, then pick
         variables: {
            options      // Options is a custom object of data used to control the pick
         },
     })
  }
/>
 

Некоторые вещи, которые я пробовал:

  • Различные политики кэширования
  • Не использовать объект для параметров и определять каждый возможный параметр как отдельную переменную

Я действительно в тупике. Похоже, в документах говорится, что новые переменные должны использоваться, если они предоставлены при повторной выборке. Я не думаю, что политика кэширования имеет отношение к делу…Я получаю свежие результаты при каждом вызове, это просто устаревшие входные переменные.

Комментарии:

1. Вы пробовали с fetch-policy = network-only также, пожалуйста, поделитесь своим кодом, как вы получаете варианты

2. если «они разные на клиенте» (проверено в теле сетевого запроса?), то это просто не проблема клиента?

3. @MuhammadBilalBangash Параметры передаются обработчику «onPick», который я опубликовал. Я могу отследить его там прямо перед вызовом ленивого запроса и увидеть, что значения в объекте «параметры» изменяются правильно. Например, в зависимости от выбранной мной кнопки это может быть { минимум: 5000 } или { минимум: 4000, максимум: 8000 }. Я могу правильно видеть эти обновления, но независимо от того, каковы они, значение, которое я отслеживаю в своем распознавателе, всегда будет таким, какими были параметры при первом вызове ленивого запроса.

4. @xadm Переменные в полезной нагрузке запроса всегда являются теми, какими они были при первом вызове ленивого запроса. Я могу отследить их на клиенте прямо перед вызовом функции ленивого запроса, и они изменятся, но к моменту отправки запроса они будут такими же, как и при первом вызове. Таким образом, проблема, по-видимому, заключается в том, что передача новых значений в функцию ленивого запроса не имеет никакого эффекта.

5. @MuhammadBilalBangash Я перепробовал все политики кэширования. Они должны сделать правильные вещи в отношении-ответов — возврата (другими словами, отсутствие кэша вызывает новый запрос, кэш-сначала просто получает кэшированный ответ). Проблема в том, что переменные, отправленные на сервер, «застревают», несмотря на то, что они отличаются при передаче в ленивую функцию.

Ответ №1:

Наверное, только pick так и называется …

… потому что для <MyBytton/> этого нет изменения реквизита, нет onPick переопределения — всегда используется первое определение обработчика (с первого рендеринга) и options состояние с одного и того же времени …

Попробуйте передать все ( options , pick и refetch ) в качестве прямых реквизитов, чтобы принудительно выполнить повторную передачу и переопределить обработчик:

 <MyButton
  options={options}
  pick={pick}
  refetch={refetch}
  onPick={(options) =>
     (refetch || pick)({ // Refetch unless this is the first click, then pick
         variables: {
            options      // Options is a custom object of data used to control the pick
         },
     })
  }
/>
 

… или [лучше] определите обработчик, прежде чем передавать его в <MyButton/> :

 const pickHandler = useCallback( 
  (options) => {
     if(refetch) {
       console.log('refetch', options);
       refetch( { variables: { options }});
     } else {
       console.log('pick', options);
       pick( { variables: { options }});
     }
  },
  [options, pick, refetch]
);

<MyButton onPick={pickHandler} />
 

Комментарии:

1. Я не могу этого сделать, потому что у меня нет вариантов, пока не нажата кнопка. Вот почему я использую ленивый обработчик. Приложение может много раз перерисовываться, прежде чем сработает «onPick».

2. … и это именно то, что вам нужно (и useCallback было разработано для этого) … обработчик обновляется только при изменении зависимости (не при каждом рендеринге) — options находится в зависимости, будет актуален при необходимости … просто попробуйте, журнал скажет правду