首页 > 解决方案 > 如何使用 Apollo Graphql 客户端和 React 解决“TypeError:无法读取未定义的属性“参数”?

问题描述

我正在尝试连接一个套牌 URL 以链接到卡片列表,类似于我在Traversy 的 SpaceX graphql demo上看到的那样。我收到错误TypeError: Cannot read property 'params' of undefined单击指向任一演示卡组的链接时。

这是我在服务器之上构建的 React 客户端,使用 Apollo 和 GraphQL 连接到我的功能性 PostgreSQL 数据库。我已经将问题定位为这些行,以及道具是如何通过 React 和 Apollo 传递的。请注意,我是 GraphQL 和 Apollo 的初学者,这是我使用 React 的第一个真正项目,因此任何理解该过程的指导将不胜感激。

let { id } = this.props.match.params;
id = parseInt(id);

甲板 index.js

    import React, { Component, Fragment } from "react";
    import gql from "graphql-tag";
    import { Query } from "react-apollo";

    import Loading from "../../Loading";
    import DeckItem from "./DeckItem";

    const GET_DECKS = gql`
      query DeckQuery {
        decks @connection(key: "DeckConnection") {
          edges {
            id
            deckName
            createdAt
            cards {
              id
              front
            }
          }
        }
      }
    `;

    class Decks extends Component {
      render() {
        return (
          <Fragment>
            <h1>Deck</h1>
            <Query query={GET_DECKS}>
              {({ data, error, loading }) => {
                if (loading) {
                  return <Loading />;
                }
                if (error) {
                  return <p>Error</p>;
                }

                const decksToRender = data.decks.edges;

                return (
                  <Fragment>
                    {console.log(data)}
                    {decksToRender.map(deck => (
                      <DeckItem key={deck.id} deck={deck} />
                    ))}
                  </Fragment>
                );
              }}
            </Query>
          </Fragment>
        );
      }
    }

    export default Decks;

甲板项目 index.js

    import React from "react";
    import Moment from "react-moment";
    import { Link } from "react-router-dom";

    export default function DeckItem({ deck: { id, deckName, createdAt } }) {
      return (
        <div>
          <div>
            <h2>
              <Link to={`/deck/${id}`}>{deckName}</Link>
            </h2>
            <p>Description coming soon...</p>
            <h5>
              Created on <Moment format="YYYY-MM-DD HH:mm">{createdAt}</Moment>
            </h5>
          </div>
        </div>
      );
    }

卡片 index.js

    import React, { Component, Fragment } from "react";
    import gql from "graphql-tag";
    import { Query } from "react-apollo";
    import { Link } from "react-router-dom";

    import Loading from "../../../Loading";

    const CARDS_QUERY = gql`
      query CardsQuery($id: ID!) {
        deck(id: $id) {
          id
          deckName
          cards {
            id
            front
            back
          }
        }
      }
    `;

    export class Cards extends Component {
      render() {
        let { id } = this.props.match.params;
        id = parseInt(id);
        return (
          <Fragment>
            <Query query={CARDS_QUERY} variables={{ id }}>
              {({ data, error, loading }) => {
                if (loading) {
                  return <Loading />;
                }
                if (error) {
                  return <p>Error</p>;
                }
                const {
                  id,
                  card: { front, back }
                } = data.deck;
                return (
                  <div>
                    <ul>
                      <h1>
                        <li>
                          <span>Id:</span> {id}
                        </li>
                      </h1>
                      <h4>Details</h4>
                      <li>Front: {front}</li>
                      <li>Back: {back}</li>
                    </ul>
                    <hr />
                    <Link to="/">Back</Link>
                  </div>
                );
              }}
            </Query>
          </Fragment>
        );
      }
    }

    export default Cards;

相关 React 路由路由

    ```
    import { Router, Route } from "react-router-dom";
    ```
    import FlashCardPage from "../FlashCards";
    import Cards from "../FlashCards/Cards/CardsItem";

    import * as routes from "../../constants/routes";

      <Router>
           ```
          <Route
            exact
            path={routes.FLASHCARDS}
            component={() => <FlashCardPage />}
          />
          <Route exact path={routes.CARDS} component={() => <Cards />} />
        </div>
      </Router>

我的路由文件中的路径是“/deck/:id”

控制台错误日志

            react-dom.development.js:19782 Uncaught TypeError: Cannot read property 'params' of undefined
                at Cards.render (index.js:23)

                index.js:1452 The above error occurred in the <Cards> component:
                in Cards (at App/index.js:42)
                in component (created by Route)
                in Route (at App/index.js:42)
                in div (at App/index.js:19)
                in Router (at App/index.js:18)
                in App (at withSession.js:8)
                in Query (at withSession.js:6)
                in Unknown (at src/index.js:84)
                in ApolloProvider (at src/index.js:83)

结果应该是一个显示卡片列表的套牌,“/deck/1”应该显示来自我的 PostgreSQL 服务器的 2 或 3 张卡片。目前我只能看到带有 url 的卡片组,但是点击后,它会立即抛出错误。其他 Graphql 函数工作正常,并且使用 Playground 查询工作得很好,所以看来我没有正确传递道具。需要任何其他信息,我很乐意提供。谢谢!

标签: reactjspostgresqlreact-routergraphqlapollo

解决方案


Route组件 fromreact-router-dom使用render-prop模式来扩展它渲染的组件,提供它props[1]

props它将这些( match, location, history, 和staticContext)转发给它在渲染时React.Component传递给它的componentprop。[2]

在您定义的路由中,这不会传递给FlashCardPageorCards组件,因为有包装它们的无状态函数组件。

<Route exact path={routes.CARDS} component={() => <Cards />} />

这个无状态的函数组件是通过这些 props 传递的;您可以负责将这些转发propsFlashCardPageCards组件。

<Route exact path={routes.CARDS} component={(props) => <Cards {...props} />} />

但是,我建议摆脱包装在中呈现的组件的无状态组件,Route因为它是多余的。

<Route exact path={routes.CARDS} component={Cards} />

推荐阅读