如何使用React-Hooks和Apollo Client在React-GraphQL中实现搜索功能?

时间:2019-04-28 13:12:39

标签: reactjs graphql react-apollo apollo-client react-hooks

我尝试使用React-Hooks和GraphQL-Apollo Client在我的管理系统中实现搜索功能。界面显示成功后,当我按“搜索”按钮时,出现了一个错误,名为:

  

无效的挂钩调用。挂钩只能在功能组件的主体内部调用。

我很确定在函数内部调用了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.log(`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
    }
 }
`;

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

根据Rules of Hooks

  

不要通过常规JavaScript函数调用Hook。相反,您可以:

     

✅从React函数组件中调用Hook。

     

✅从自定义挂钩中调用挂钩(我们将在下一页中了解它们)。

如果您需要在事件响应中手动调用查询,请直接使用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)
        ...
      }} />

答案 1 :(得分:0)

我在第二个答案中发现了问题,应该在执行之前包装一个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;

答案 2 :(得分:0)

您可以使用useLazyQuery方法并将数据对象公开给整个组件。

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.log(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. -
 );
}

与执行 useQuery 相对, useLazyQuery 方法将仅在点击时执行

此时可以传递“名称”值作为参数。

例如,如果您改用 useQuery ,并且具有查询中必需的参数(即String!),则useQuery方法将为您提供错误信息。因为在组件渲染中它将尝试在没有必需参数的情况下直接运行该查询,因为在该时间段尚不可用。