Условная выборка tRPC v10 с использованием useQuery и обязательными параметрами

Я пытаюсь понять, как использовать интеграцию @tanstack/react-query для tRPC, когда у меня есть условные выборки с обязательными параметрами.

Например, скажем, у меня есть этот бэкэнд:

// Backend
export const t = initTRPC.create();
export const appRouter = t.router({
  hello: t.procedure.input(
    z.object({ text: z.string() })
  ).query((opts) => {
    return {
      greeting: `hello ${opts.input.text}`,
    };
  }),
});

Обратите внимание, что параметр text является обязательным.

Теперь предположим, что у меня есть этот интерфейс:

// Frontend
export const trpc = createTRPCReact<typeof appRouter>();

function MyComponent() {
  const [text, setText] = useState<string | null>(null)

  const {data: helloData} = trpc.hello.useQuery({ text }) // type error

  return <>
    <div>{helloData.greeting}</div>
    <button onClick = {() => setText('a')}>a</button>
    <button onClick = {() => setText('b')}>b</button>
    <button onClick = {() => setText(null)}>none</button>
  </>
}

Здесь text начинается как null, поэтому я не могу вызвать запрос trpc.hello, пока он не получит значение. Итак, Typescript справедливо жалуется:

Type 'string | null' is not assignable to type 'string'.
  Type 'null' is not assignable to type 'string'.(2322)

Итак, как мне выполнить этот запрос условно?

Я не могу условно выполнить запрос:

if (text !== null) trpc.hello.useQuery({ text }) // breaks rules of hooks

По правилам крючков.

И это это:

const { data: helloData } = trpc.hello.useQuery(
  { text }, // type error, but works
  { enabled: text !== null }
)

Работает во время выполнения, но ошибка Typescript все еще существует, поскольку он не может точно знать, что объект, как ожидается, будет недействительным, если он не будет использоваться.

Итак, как правильно получить tRPC по условию useQuery?

Полный код с ошибкой типа на машинописной площадке


Стоит отметить, что в tRPC v11 для этого есть новая функция: https://trpc.io/docs/client/react/disabling-queries

Но я пока застрял на v10 из-за других зависимостей, которые еще не совместимы.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я вижу два пути решения этой проблемы:

Первый — использовать useQuery с условием активации:

const { data: helloData } = trpc.myRoute.hello.useQuery(
{ text },
{
    enabled: text !== null,
}
)

Второй — использовать useUtils:

function ComponentWithUseUtils() {
    const [text, setText] = useState<string | null>(null)
    const [result, setResult] = useState<string | null>(null)
    const utils = trpc.useUtils()
    const handleQuery = () => {
        if (!text) return
        utils.myRoute.hello.fetch({ text }).then(data => {
            setResult(data.greeting)
        })
    }
    return (
        <>
            <input type = "text" onChange = {e => setText(e.target.value)} className = "border-1 p-2" />
            <button onClick = {handleQuery} className = "bg-red-100 p-2">
                Send
            </button>
            {result}
        </>
    )
}

см.: https://trpc.io/docs/v10/client/react/useUtils

useQuery — ваш помощник в управлении получением данных с помощью React Query. Он заботится о таких вещах, как поддержание актуальности данных и их автоматическое обновление.

useUtils позволяет вам взять на себя управление получением данных. Это удобно, если вы хотите запускать обновление данных на основе действий пользователя, например нажатий кнопок, а не только при загрузке компонента.

Ваш первый вариант был рассмотрен в моем вопросе и представляет собой ошибку типа в Typescript, которую, похоже, не существует простого способа решить. А второй вариант означает отказ от всего, что касается реагирования на запросы, верно?

Alex Wayne 31.05.2024 00:14

Вот пример ввода первого метода: const { data: helloData } = trpc.project.hello.useQuery({ text } as { text: string }, { Enabled: text !== null, }) useQuery отлично подходит для автоматическая выборка данных, поддержание свежести и синхронизация с сервером. Но он не идеален для всего. useUtils позволяет вам взять на себя управление, когда вам нужно получить данные на основе действий пользователя, например, нажатий кнопок, а не только при загрузке компонента, а также использует ответный запрос под капотом.

rooklee 31.05.2024 01:59
Ответ принят как подходящий

для v10 вы можете использовать оператор Bang:

const { data: helloData } = trpc.hello.useQuery(
  { text: text! },
  { enabled: text !== null }
)

или пропишите свою схему в бэкенде, чтобы она тоже принимала null, но потом выдавала ошибку.

Стоит отметить, что в tRPC v11 для этого есть новая функция: https://trpc.io/docs/client/react/disabling-queries

Лучше всего, конечно, обновиться до v11 и использовать skipToken, но вы это уже знаете :)

Другие вопросы по теме