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

Posted

技术标签:

【中文标题】如何使用 Apollo Graphql 客户端和 React 解决“TypeError:无法读取未定义的属性“参数”?【英文标题】:How to solve 'TypeError: Cannot read property 'params' of undefined' with Apollo Graphql Client and React? 【发布时间】:2019-05-28 19:54:06 【问题描述】:

我正在尝试连接一个套牌 URL 以链接到卡片列表,类似于我在 Traversy's 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);

甲板索引.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;

DeckItem 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 查询工作得很好,所以看来我没有正确传递道具。需要任何其他信息,我很乐意提供。谢谢!

【问题讨论】:

【参考方案1】:

来自react-router-domRoute 组件使用render-prop 模式来扩展它所呈现的组件,提供props[1]

它将这些 propsmatchlocationhistorystaticContext)转发到 React.Component,它在渲染时传递给它的 component 属性。 [2]

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

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

这个无状态的函数组件被传递了这些props;您可以负责将这些props 转发到FlashCardPageCards 组件。

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

但是,我建议去掉封装Route 中呈现的组件的无状态组件,因为它是多余的。

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

【讨论】:

谢谢,您的指示非常有效,帮助我理解了为什么我无法让它工作!您关于摆脱无状态组件的建议我当然也会遵循。

以上是关于如何使用 Apollo Graphql 客户端和 React 解决“TypeError:无法读取未定义的属性“参数”?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 React-Apollo 处理 GraphQL 错误?

GraphQL:Apollo 客户端缓存如何工作以保持与服务器的数据一致性?

在客户端解析器中导入类型时,如何避免使用 Apollo 客户端和“graphql-codegen”的角度项目中的循环依赖?

如何使用 apollo 客户端在 graphql 的角度处理错误?

如何使用 apollo 客户端库创建带有角度参数的 graphql 查询

使用 Apollo Server 时如何生成 schema.graphql 文件?