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

Posted

技术标签:

【中文标题】如何使用 React-Hooks 和 Apollo Client 在 React-GraphQL 中实现搜索功能?【英文标题】:How to implement Search Function in React-GraphQL using React-Hooks and Apollo Client? 【发布时间】:2019-09-17 07:48:08 【问题描述】:

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

无效的挂钩调用。 Hooks 只能在函数组件内部调用。

我很确定 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
    
 
`;

感谢并感谢您的帮助!

【问题讨论】:

【参考方案1】:

根据Rules of Hooks:

不要从常规 javascript 函数中调用 Hooks。相反,您可以:

✅ 从 React 函数组件调用 Hooks。

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

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

【讨论】:

感谢您的帮助!我已经摆脱了错误!还有一个问题,当我执行查询时,我的“数据”总是未定义,我的查询有问题吗?我已经更新了我在问题中的查询,谢谢! 我已经找到第二个问题的答案了,感谢您的帮助!【参考方案2】:

您可以使用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 方法将为您提供错误。因为在组件渲染时,它会尝试直接运行该查询而不需要所需的参数,因为在那段时间它还不可用。

【讨论】:

【参考方案3】:

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

【讨论】:

以上是关于如何使用 React-Hooks 和 Apollo Client 在 React-GraphQL 中实现搜索功能?的主要内容,如果未能解决你的问题,请参考以下文章

@apollo/react-hooks 中的 `useSubscription` 方法加载卡住

使用 Jest 模拟 @apollo/react-hooks useQuery

使用@apollo/react-hooks,react 应用程序在刷新过期时严重崩溃

使用 graphql-tools、apollo-link-schema 和 react-hooks 在模拟时总是返回 undefined

有没有办法使用 @apollo/react-hooks 访问多个 graphql 突变的选项

在@apollo/react-hooks 的 useQuery 钩子中忽略了跳过参数