You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+GraphQL项目报getUserLocation is not a function与400错误

问题根因

两个报错均为Apollo Client使用方式错误导致,具体问题点:

  • useQuery 是React Hook,执行后返回的是包含data/loading/error的状态对象,不是可执行函数,把它当函数调用就会触发getUserlocation is not a function报错
  • GraphQL查询语句未声明location入参,前端传参时后端无法识别参数定义,直接返回400 Bad Request
  • 混淆了useQuery(组件挂载时自动执行查询)和useLazyQuery(手动触发查询)的适用场景:搜索功能需要用户输入关键词、点击提交后才执行查询,不适合用useQuery
  • 自定义Hook逻辑错误,且未在组件中正确引入,反而在组件里直接解构useQuery返回值中不存在的getLocation方法;同时把Apollo返回结果当成fetch风格的Response对象做解析,逻辑完全不匹配。
修正方案

1. 修正GraphQL查询定义(queries.js)

给查询加上location入参声明,和后端接收的参数名保持一致:

import { gql } from "@apollo/client";

export const QUERY_GET_LOCATIONS = gql`
  query getUserLocation($location: String!) {
    getUserLocation(location: $location) {
      _id
      username
      bio
    }
  }
`;

注意:如果后端接口的location参数不是必填项,把String!里的感叹号去掉即可,常规搜索逻辑下该参数设为必填。

2. 移除无效的自定义Hook

之前写的useUserLocation自定义Hook逻辑完全错误,直接删除即可,不需要保留。

3. 修正SearchMenu.js组件逻辑

把错误的useQuery用法替换为useLazyQuery实现手动触发查询,移除fetch风格的响应解析逻辑,Apollo会直接返回结构化的查询结果:

import React, { useState } from "react";
import {
  Jumbotron,
  Container,
  Col,
  Form,
  Button,
  Card,
  CardColumns,
} from "react-bootstrap";
import { QUERY_GET_LOCATIONS } from "../util/queries";
import { useLazyQuery } from "@apollo/client";

const SearchedUsers = () => {
  const [searchedUsers, setSearchedUsers] = useState([]);
  const [searchInput, setSearchInput] = useState("");
  // useLazyQuery返回查询触发函数和查询状态,第一个返回值就是可手动调用的查询方法
  const [getLocation, { loading }] = useLazyQuery(QUERY_GET_LOCATIONS);

  const handleFormSubmit = async (event) => {
    event.preventDefault();
    if (!searchInput) {
      return false;
    }
    try {
      // 触发查询,传入location变量
      const { data } = await getLocation({ variables: { location: searchInput } });
      // 直接从data字段取后端返回数据,不需要调用.json()、也不需要判断response.ok
      const userData = data?.getUserLocation?.map((user) => ({
        userId: user._id,
        userName: user.username || "No user to display",
        bio: user.bio || "No bio available"
      })) || [];

      setSearchedUsers(userData);
      setSearchInput("");
    } catch (err) {
      console.error(err);
    }
  };

  return (
    <>
      <Jumbotron fluid className="text-light bg-dark">
        <Container>
          <h1>Search for Location!</h1>
          <Form onSubmit={handleFormSubmit}>
            <Form.Row>
              <Col xs={12} md={8}>
                <Form.Control
                  name="searchInput"
                  value={searchInput}
                  onChange={(e) => setSearchInput(e.target.value)}
                  type="text"
                  size="lg"
                  placeholder="Search for a location"
                />
              </Col>
              <Col xs={12} md={4}>
                <Button type="submit" variant="success" size="lg" disabled={loading}>
                  {loading ? "Searching..." : "Submit Search"}
                </Button>
              </Col>
            </Form.Row>
          </Form>
        </Container>
      </Jumbotron>

      <Container>
        <h2>
          {searchedUsers.length
            ? `Viewing ${searchedUsers.length} results:`
            : "Search for a location to begin"}
        </h2>
        <CardColumns>
          {searchedUsers.map((user) => {
            return (
              <Card key={user.userId} border="dark">
                <Card.Body>
                  <Card.Title>{user.userName}</Card.Title>
                  <p className="small">Bio: {user.bio}</p>
                </Card.Body>
              </Card>
            );
          })}
        </CardColumns>
      </Container>
    </>
  );
};

export default SearchedUsers;
补充说明
  • 所有Apollo Hook返回的查询结果都不是fetch风格的Response对象,不要用response.ok或者response.json()做解析,直接从返回结果的data字段取后端返回的数据即可
  • 带参数的GraphQL查询必须先在gql语句中声明参数的名称、类型,再传入对应查询字段中,否则后端会直接返回400错误
  • 需要用户交互后才触发的查询,统一用useLazyQuery实现,不要基于useQuery手动封装调用逻辑,很容易触发Hook调用顺序错误的问题。

内容的提问来源于stack exchange,提问作者FaustoLopez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:09:20