有条件地调用 useQuery 会导致构建失败

Posted

技术标签:

【中文标题】有条件地调用 useQuery 会导致构建失败【英文标题】:Calling useQuery conditionally results into build failures 【发布时间】:2020-11-15 19:04:09 【问题描述】:

我有一个用例,我在 UI 中显示与用户关联的所有待办事项列表。有一个切换按钮,切换它,仅显示同一用户的 completed 待办事项列表。我正在调用 react hook useQuery有条件 基于切换按钮状态。下面是代码:

import TodoItems from './TodoItems';
import  LIST_TODOS_BY_USERNAME, LIST_TODOS_BY_STATUS  from '../graphql/queries';
import  useQuery  from '@apollo/react-hooks';

type TodoListProps = 
  username: string;
  showCompleted: boolean;
;

const TodoList:FC<TodoListProps> = ( username, showCompleted ) => 
  const  loading, error, data  = !showCompleted
    ? useQuery(LIST_TODOS_BY_USERNAME,  variables:  username , pollInterval: 500 )
    : useQuery(LIST_TODOS_BY_STATUS,  variables:  username, status: 'COMPLETED' , pollInterval: 500 );

  if (error) 
    return (
      <div>
        <p>`Error! $error`</p>
      </div>
    );
  

  return (
    <div className="todoapp">
      <div>
        <header className="header">
          <div className="imagetool">
            <img
              alt=username
              src=`https://something.com/?uid=$username`
            />
          </div>
          <H1>
            username
            &rsquo;s todos
          </H1>
          <div className="todo-list-container">
            <Row gridGap=32 justifyContent="center" padding=8>
              <View>
                loading ? (
                  <Col alignItems="start" gridGap=16>
                    <Spinner size=SpinnerSize.Small />
                  </Col>
                ) : (
                  <TodoItems todoListItems=!showCompleted ? data.getTodosByUserName : data.getTodosByStatus />
                )
              </View>
            </Row>
          </div>
        </header>
      </div>
    </div>
  );
;

export default TodoList;

然而,这很好用,但在构建过程中,由于 linting 开始发挥作用,它失败并出现错误:

17:7 错误 React Hook "useQuery" 被有条件地调用。 React Hooks 必须在每个组件渲染中以完全相同的顺序调用 react-hooks/rules-of-hooks

如何在不禁用 lint 规则的情况下解决问题?

任何指针表示赞赏!

【问题讨论】:

【参考方案1】:

在 React 中,钩子需要总是被调用——因此它们应该只在某些时候被调用(=有条件地)。这甚至适用于使用相同钩子函数的钩子(useQuery() 与您的情况一样)。要在每个渲染迭代中调用非常相似useQuery(),请使用一个钩子;因此

改变这个

  const  loading, error, data  = !showCompleted
    ? useQuery(LIST_TODOS_BY_USERNAME,  variables:  username , pollInterval: 500 )
    : useQuery(LIST_TODOS_BY_STATUS,  variables:  username, status: 'COMPLETED' , pollInterval: 500 );

到这里:

  const  loading, error, data  = useQuery(
    !showCompleted ? LIST_TODOS_BY_USERNAME : LIST_TODOS_BY_STATUS,
    
      variables: !showCompleted
        ?  username 
        :  username, status: 'COMPLETED' ,
      pollInterval: 500,
    
  )

【讨论】:

【参考方案2】:

不要有条件地使用 useQuery。您有两种选择,要么将查询作为 prop 的值获取,要么将查询的名称存储在组件的状态中并根据需要进行更改。

【讨论】:

以上是关于有条件地调用 useQuery 会导致构建失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 react/apollo 中调用条件 useQuery 钩子

Apollo-client 有条件地同时运行 useLazyQuery 和 useQuery - 最好的方法是啥?

当输入变量相同时,Apollo useQuery 不会进行网络调用

接口返回失败是啥意思

状态变化时如何防止 useQuery 运行?

为啥添加额外的标头会导致 AJAX 调用失败