useQuery 有条件地渲染数据

useQuery to conditionally render data

我正在尝试使用 useQueryGET 来自我的数据库的数据,然后在我的 REACT 组件中呈现数据,但我一直从我的 JSX 收到长度未定义的错误。谁能看看我对 useQuery 的使用是否不正确?

const SavedBooks = () => {
  const [userData, setUserData] = useState({});
  const { loading, data } = useQuery(GET_ME);
  console.log(loading)
  console.log(data?.me)
  if (loading) {
    return <h2>LOADING...</h2>
  } else {
    setUserData(data?.me);
  }

  // create function that accepts the book's mongo _id value as param and deletes the book from the database
  const handleDeleteBook = async (bookId) => {
    const token = Auth.loggedIn() ? Auth.getToken() : null;

    if (!token) {
      return false;
    }

    try {
      const response = await deleteBook(bookId, token);

      if (!response.ok) {
        throw new Error('something went wrong!');
      }

      const updatedUser = await response.json();
      setUserData(updatedUser);
      // upon success, remove book's id from localStorage
      removeBookId(bookId);
    } catch (err) {
      console.error(err);
    }
  };

  return (
        <>
          <Jumbotron fluid className='text-light bg-dark'>
            <Container>
              <h1>Viewing saved books!</h1>
            </Container>
          </Jumbotron>
            <Container>
              <h2>
                  {userData?.savedBooks.length
                    ? `Viewing ${userData.savedBooks.length} saved ${userData.savedBooks.length === 1 ? 'book' : 'books'}:`
                    : 'You have no saved books!'}
              </h2>
              <CardColumns>
                {userData?.savedBooks.map((book) => {
                  return (
                    <Card key={book.bookId} border='dark'>
                      {book.image ? <Card.Img src={book.image} alt={`The cover for ${book.title}`} variant='top' /> : null}
                      <Card.Body>
                        <Card.Title>{book.title}</Card.Title>
                        <p className='small'>Authors: {book.authors}</p>
                        <Card.Text>{book.description}</Card.Text>
                        <Button className='btn-block btn-danger' onClick={() => handleDeleteBook(book.bookId)}>
                          Delete this Book!
                        </Button>
                      </Card.Body>
                    </Card>
                  )
                })}
              </CardColumns>
            </Container>
        </>
  );
};

数据最终会自己记录在控制台中,但它不会阻止我的 JSX 渲染,所以我最终在这个区域周围得到一个 Cannot read property 'length' of undefined

              <h2>
                  {userData?.savedBooks.length
                    ? `Viewing ${userData.savedBooks.length} saved ${userData.savedBooks.length === 1 ? 'book' : 'books'}:`
                    : 'You have no saved books!'}
              </h2>

错误发生是因为在某个时候savedBooks = undifiend 所以你需要做的就是检查它是否是,只需添加另一个 ?

userData?.savedBooks?.length

<h2>
  {loading ? 'LOADING...' : 
    userData?.savedBooks?.length ? 
    `Viewing ${userData.savedBooks.length} saved ${userData.savedBooks.length === 1 ? 'book' : 'books'}:`
    : 'You have no saved books!'}
</h2>

代码中还有一些地方可能会给你带来问题 您不应该直接在功能组件体内使用 setUserData ,这会导致不必要的重新提交或进入无限渲染循环。

我建议这样做:

useEffect(() => {
  setUserData(data?.me);
}, [data]);

这将使组件仅在 data 更改时呈现。