Как реализовать функцию поиска в React-GraphQL, используя React-Hooks и клиент Apollo?

Я пытаюсь внедрить функцию поиска в свою систему управления, используя React-Hooks и клиент GraphQL-Apollo. Хотя интерфейс отображается успешно, когда я нажимаю кнопку «Поиск», выдается ошибка с именем:

Invalid hook call. Hooks can only be called inside of the body of a function component.

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

Я пробовал несколько способов реализовать функцию поиска и искать в Интернете, но все еще не мог решить ее. Я тоже впервые сталкиваюсь с React-Hooks.

Вот мой текущий код в компоненте searchUser

import React from 'react'
import {useQuery} from 'react-apollo-hooks';
import {searchUserQ} from '../queries/queries';

const SearchUserForm = () => {
    let name = '';
    let content;

return (
    <div id = "edit-user">
        <div className = "field">
            <label htmlFor = "name">Search UserName</label>
            <input type = "text" id = "name" onChange = { (event) => {
                name = event.target.value }}/>
            <button onClick = {(event) => {
                event.preventDefault();
                const { data, loading, error } = useQuery(searchUserQ, {
                    variables: { name: name },
                    suspend: false
                });

                if (loading) {
                    content = <p>Loading User...</p>
                }

                if (error){
                    console.info(`Error Occur: ${ error }`);
                    content = <p>Error Occur!</p>
                }

                content = data.users.map(user => (
                    <p key = {user.id}>Username: {user.name}    ID: {user.id}</p>
                ));
            }}>
                Submit
            </button>
            <p>{ content }</p>
        </div>
    </div>
)
}

export default SearchUserForm;

Может кто-нибудь помочь с этим?

Еще один вопрос заключается в том, что мой data, похоже, возвращает undefined каждый раз, когда я выполняю запрос. Что-то не так с моим запросом? Вот запрос:

const searchUserQ = gql`
query User($name: String!){
    user(name: $name){
        id
        name
        email
    }
 }
`;

Спасибо и признателен за помощь!

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

Ответы 3

Ответ принят как подходящий

Согласно Правила хуков:

Don’t call Hooks from regular JavaScript functions. Instead, you can:

✅ Call Hooks from React function components.

✅ Call Hooks from custom Hooks (we’ll learn about them on the next page).

Если вам нужно вручную вызвать запрос вручную в ответ на событие, используйте клиент Apollo напрямую. Вы можете использовать useApolloClient, чтобы получить экземпляр клиента внутри вашего компонента:

const SearchUserForm = () => {
  const client = useApolloClient();
  ...
    return (
      ...
      <button onClick = {async (event) => {
        try {
          const { data } = client.query({
            query: searchUserQ,
            variables: { name: event.target.value },
          });
          // Do something with data, like set state
        catch (e) {
          // Handle errors
        }
      }} />

Вы также можете использовать useQuery, например:

const SearchUserForm = () => {
  const [name, setName] = useState('')
  const { data, loading, error } = useQuery(searchUserQ, {
    variables: { name },       
  });
  ...
    return (
      ...
      <button onClick = {async (event) => {
        setName(event.target.value)
        ...
      }} />

Спасибо за помощь! Я избавился от ошибки уже! Еще один вопрос: мои «данные» всегда не определены, когда я выполняю запрос, что-то не так с моим запросом? Я обновил свой запрос в вопросе, спасибо!

Corene 29.04.2019 09:37

Я нашел ответ на свой второй вопрос, спасибо за помощь!

Corene 29.04.2019 10:33

Я обнаружил проблему со своим вторым ответом, нужно просто обернуть оператор if перед его выполнением, вот полный код:

import React, {useState} from 'react'
import {useQuery} from 'react-apollo-hooks';
import {searchUserQ} from '../queries/queries';

const SearchUserForm = () => {

const [name, setName] = useState('');
const { data, error, loading } = useQuery(searchUserQ, {
    variables: { name }
});

let content;
let sName;

if (data.user !== undefined && data.user !== null) {
    if (loading) { content = 'Loading User...' }

    if (error) { content = `Error Occur: ${error}` }

    const user = data.user;
    content = `Username: ${ user.name }    ID: ${ user.id }`
}

return (
    <div id = "edit-user">
        <div className = "field">
            <label htmlFor = "name">Search UserName</label>
            <input type = "text" id = "name" onChange = {(event) => {
                sName = event.target.value;
            }}/>
            <button onClick = {(event) => {
                setName(sName);
            }} value = {name}>
                Search
            </button>
        </div>
        <div>
            <p>{ content }</p>
        </div>
    </div>
)

};

export default SearchUserForm;

Вы можете использовать метод использоватьLazyQuery и предоставить свой объект данных всему компоненту.

import {useLazyQuery} from '@apollo/react-hooks';
// - etc. -

const SearchUserForm = () => {
 // note: keep the query hook on the top level in the component
 const [runQuery, { data, loading, error }] = useLazyQuery(searchUserQ);

 // you can now just use the data as you would regularly do: 
 if (data) {
   console.info(data);
 }

 return (
   <div id = "edit-user">
     <div className = "field">
        <label htmlFor = "name">Search UserName</label>
        <input
          type = "text"
          id = "name"
          onChange = {(event) => {name = event.target.value }} />
        <button onClick = {
          (event) => {
            event.preventDefault();
            // query is executed here
            runQuery({
              variables: { name }, // note: name = property shorthand
              suspend: false
            })
          }}>
          // - etc. -
 );
}

В отличие от использовать запрос, метод использоватьLazyQuery будет выполняться только по клику.

В тот момент, когда вы можете передать значение «имя» в качестве параметра.

Если, например, вместо этого вы будете использовать использовать запрос и у вас есть параметр, который требуется в вашем запросе (например, String!), метод useQuery выдаст вам ошибку. Потому что при рендеринге компонента он попытается запустить этот запрос напрямую без обязательного параметра, потому что в этот период времени он еще недоступен.

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