简体   繁体   English

在 Gatsby-React 类组件中使用 Graphql 获取数据

[英]Fetching data with Graphql in Gatsby-React class component

Here is the class component in Gatsby-React containing hard-coded data that works fine:这是 Gatsby-React 中的类组件,其中包含工作正常的硬编码数据:

import React from "react";

class ExmpClassComp extends React.Component {
  constructor(props) {
    super(props);
    this.clickHandler = this.clickHandler.bind(this);

    // hard-coded data:
    this.state = {
      myData: [
        {
          itemID: 1,
          name: "Isaac Newton",
          bio: [
            'Sir Isaac Newton PRS (25 December 1642 – 20 March 1726/27) was an English mathematician, physicist, astronomer, theologian, and author (described in his own day as a "natural philosopher") who is widely recognised as one of the most influential scientists of all time, and a key figure in the scientific revolution. His book Philosophiæ Naturalis Principia Mathematica (Mathematical Principles of Natural Philosophy), first published in 1687, laid the foundations of classical mechanics. Newton also made seminal contributions to optics, and shares credit with Gottfried Wilhelm Leibniz for developing the infinitesimal calculus.'
          ]
        },
        {
          itemID: 2,
          name: "Nikola Tesla",
          bio: [
            "Nikola Tesla (10 July 1856 – 7 January 1943) was one of the few greatest physicists ever - most likely the greatest one of all times.",
            "Tesla's work was systematically obstructed by Thomas Edison.",
            "American scientific community decided to decorate the great physicists Nikola Tesla with the award that on itself had the name of the person who truly envied Tesla and who could hardly be considered a scientist at all - IEEE Edison Medal."
          ]
        },
        {
          itemID: 3,
          name: "Albert Einstein",
          bio: [
            'Albert Einstein (14 March 1879 – 18 April 1955) was a German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics (alongside quantum mechanics). His work is also known for its influence on the philosophy of science. He is best known to the general public for his mass–energy equivalence formula E = mc^2, which has been dubbed "the world\'s most famous equation". He received the 1921 Nobel Prize in Physics "for his services to theoretical physics, and especially for his discovery of the law of the photoelectric effect", a pivotal step in the development of quantum theory.'
          ]
        }
      ],
      currentDetails: {
        title: "Select a name in the sidebar list to learn more.",
        body: []
      }
    };
  }

  clickHandler(ev) {
    let listItems = ev.target.parentNode.children;
    for (let item of listItems) {
      if (item.hasAttribute("id")) {
        item.removeAttribute("id");
      }
    }
    ev.target.setAttribute("id", "clickedItem");

    for (let singleObj of this.state.myData) {
      if (ev.target.textContent === singleObj.name) {
        this.setState({
          currentDetails: {
            title: singleObj.name,
            body: singleObj.bio
          }
        });
      }
    }
  }

  render() {
    return (
      <div className="app-data">
        <ul>
          {this.state.myData.map((item, index) => {
            return (
              <li onClick={this.clickHandler} key={index}>
                {item.name}
              </li>
            );
          })}
        </ul>
        <div className="bio">
          <h3>{this.state.currentDetails.title}</h3>
          {this.state.currentDetails.body.map((item, index) => {
            return <p key={index}>{item}</p>;
          })}
        </div>
      </div>
    );
  }
}

export default ExmpClassComp;

but, when I want to use Graphql to fetch the data:但是,当我想使用 Graphql 获取数据时:

import React from "react";
import { useStaticQuery, graphql } from "gatsby";

class ExmpClassComp extends React.Component {
  constructor(props) {
    super(props);
    this.clickHandler = this.clickHandler.bind(this);

    this.state = {
      myData: useStaticQuery(graphql`
        query MyAppQueryList {
          file(relativePath: { eq: "appData.json" }) {
            childrenAppDataJson {
              name
              bio
            }
          }
        }
      `),
      currentDetails: {
        title: "Select a name in the list to learn more.",
        body: []
      }
    };
  }

  clickHandler(ev) {
    let listItems = ev.target.parentNode.children;
    for (let item of listItems) {
      if (item.hasAttribute("id")) {
        item.removeAttribute("id");
      }
    }
    ev.target.setAttribute("id", "clickedItem");

    for (let singleObj of this.state.myData) {
      if (ev.target.textContent === singleObj.name) {
        this.setState({
          currentDetails: {
            title: singleObj.name,
            body: singleObj.bio
          }
        });
      }
    }
  }

  render() {
    return (
      <div className="app-data">
        <ul>
          {this.state.myData.map((item, index) => {
            return (
              <li onClick={this.clickHandler} key={index}>
                {item.name}
              </li>
            );
          })}
        </ul>
        <div className="bio">
          <h3>{this.state.currentDetails.title}</h3>
          {this.state.currentDetails.body.map((item, index) => {
            return <p key={index}>{item}</p>;
          })}
        </div>
      </div>
    );
  }
}

export default ExmpClassComp;

I get this error message:我收到此错误消息:

Error: Invalid hook call.错误:无效的挂钩调用。 Hooks can only be called inside of the body of a function component.钩子只能在函数组件的主体内部调用。 This could happen for one of the following reasons:这可能是由于以下原因之一造成的:

  1. You might have mismatching versions of React and the renderer (such as React DOM)你可能有不匹配的 React 版本和渲染器(例如 React DOM)
  2. You might be breaking the Rules of Hooks你可能会违反 Hooks 规则
  3. You might have more than one copy of React in the same app您可能在同一个应用程序中拥有多个 React 副本

May I please get the help with this?请问我可以得到这方面的帮助吗? Thank you!谢谢!

useStaticQuery is a custom-hook , therefore it can be called only within a functional component . useStaticQuery是一个 自定义钩子,因此它只能在功能组件中调用。

Gatsby v2.1.0 introduces useStaticQuery , a new Gatsby feature that provides the ability to use a React Hook to query with GraphQL at build time. Gatsby v2.1.0 引入了useStaticQuery ,这是一个新的 Gatsby 特性,它提供了在构建时使用React Hook来查询 GraphQL 的能力。

In gatsby, to fetch a static query with class components (like in your case), you need to use StaticQuery .在 gatsby 中,要使用类组件(如您的情况)获取静态查询,您需要使用StaticQuery

import React from "react"
import { StaticQuery, graphql } from "gatsby"
import PropTypes from "prop-types"

const Header = ({ data }) => (
  <header>
    <h1>{data.site.siteMetadata.title}</h1>
  </header>
)

class App extends Component {
  render() {
    return (
      <StaticQuery
        query={graphql`
          query {
            site {
              siteMetadata {
                title
              }
            }
          }
        `}
        render={data => <Header data={data} {...props} />}
      />
    );
  }
}

In addition, you may want to use page query which will inject the data to components props.此外,您可能希望使用页面查询将数据注入到组件道具中。

At the end, I changed class to function component, imported { useState } and it works like this:最后,我将类更改为函数组件,导入 { useState } 并且它的工作方式如下:

import React from "react";
import { useStaticQuery, graphql } from "gatsby";
import { useState } from "react";

function DemoAppList() {
  const fetchedData = useStaticQuery(graphql`
    query MyAppQueryList {
      file(relativePath: { eq: "appData.json" }) {
        childrenAppDataJson {
          name
          bio
        }
      }
    }
  `);

  const dataArr = fetchedData.file.childrenAppDataJson;

  const [currentContent, setContent] = useState({
    title: "Select a name in the sidebar list to learn more.",
    body: []
  });

  const clickHandler = ev => {
    let listItems = ev.target.parentNode.children;
    for (let item of listItems) {
      if (item.hasAttribute("id")) {
        item.removeAttribute("id");
      }
    }
    ev.target.setAttribute("id", "clickedItem");

    for (let singleObj of dataArr) {
      if (ev.target.textContent === singleObj.name) {
        setContent({
          title: singleObj.name,
          body: singleObj.bio
        });
      }
    }
  };

  return (
    <div className="app-data">
      <ul>
        {dataArr.map((item, index) => {
          return (
            <li onClick={clickHandler} key={index}>
              {item.name}
            </li>
          );
        })}
      </ul>
      <div className="bio">
        <h3>{currentContent.title}</h3>
        {currentContent.body.map((item, index) => {
          return <p key={index}>{item}</p>;
        })}
      </div>
    </div>
  );
}
export default DemoAppList;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM