简体   繁体   中英

Programmatically create Gatsby pages from API data

This is a similar question to this .

I'm looking for help programmatically creating pages using createPage or createPages and am having trouble - the docs give an example for creating pages from markdown files but not much explanation.

I am using a plugin in plugins\\characters\\gatsby-node.js to add data from the Rick & Morty API to the GraphQL data layer. My plugin is at the bottom of the question in case it is relevant.

The plugin does add the data successfully as I can see the data in http://localhost:8000/___graphql , and I have successfully managed to use the data in (static) pages.

Where I am lost is that I would like to be able to create a page for each individual character, using the url characters/<characterIdHere> for each of the pages. I am aware that I need to add some logic to my (main or plugins version of....?) gatsby-node.js file, but this is the part I am stuck on. I do not know what I need to put into the gatsby-node.js file. The examples I can find all use json or markdown files and I would like to use data that I have pulled in (from an API) to gatsby's data layer. I have obviously researched this for a few hours and played around with it before asking, but not had any luck.

The component on the pages I would like to create should look something like this:

const CharactersViewSingle = ({ character}) => {
  return (
    <div>
      <Helmet>
        <title>{character.name && character.name}</title>
      </Helmet>
      <NavBar />
      <CharactersViewBox character={character} width={300} height={520} />
    </div>
  )
}

The above code is taken from what the component returned when I was using create-react-app.

The graphQL query (which obviously reflects the structure of the data I would like to use) I use to get the data on other (static) pages looks like this:

export const query = graphql`
  query CharactersQuery {
    allCharacters(limit: 5) {
      edges {
        node {
          id
          name
          status
          gender
          image
        }
      }
    }
  }
`

Plugin code:

const axios = require("axios")

exports.sourceNodes = async ({
  actions,
  createNodeId,
  createContentDigest,
}) => {
  const { createNode } = actions

  const integerList = (start, length) =>
    Array.from({ length: length }, (v, k) => k + start)

  const rickMortyURL = `https://rickandmortyapi.com/api/character/${integerList(
    1,
    493
  )}`

  const rickMorty = await axios.get(rickMortyURL)
  const query = await axios.get(rickMortyURL)
  rickMorty.data.forEach(character => {
    const nodeContent = JSON.stringify(character)
    const nodeMeta = {
      id: character.id.toString(),
      //id: createNodeId(`char-data-${character.id}`),
      parent: null,
      children: [],
      internal: {
        type: `Characters`,
        content: nodeContent,
        contentDigest: createContentDigest(character),
      },
    }
    const node = Object.assign({}, character, nodeMeta)
    createNode(node)
  })
}

Gatsby's createPages API is what you might be looking for.

I used it to create multiple pages like blog1, blog2, blog3 etc... In the same way, you can create multiple pages for your characters.

Since you mentioned you have a graphql call to get your characters using

const pages = await graphql(`
 query CharactersQuery {
    allCharacters(limit: 5) {
      edges {
        node {
          id
          name
          status
          gender
          image
        }
      }
    }
  }
`)

The above graphql call returns results in pages.data.allCharacters.edges

Now you can iterate them using foreach and use createPage to create the pages.

Below is complete mock code you might need to add in your gatsby-node.js file

    const path = require('path');

    exports.createPages = async ({ graphql, actions }) => {
      const { createPage } = actions
      const templateOfYourCharacterPage = path.resolve(`src/templates/exampleTemplateFile.jsx`)

    const pages = await graphql(`
     query CharactersQuery {
        allCharacters(limit: 5) {
          edges {
            node {
              id
              name
              status
              gender
              image
            }
          }
        }
      }
    `)

      let characters = pages.data.allCharacters.edges;

      characters.forEach(edge => {
        createPage({
          path: `/${edge.node.id}`,
          component: templateOfYourCharacterPage,
          context: {id: edge.node.uid, name: edge.node.name } // This is to pass data as props to your component.
        })
      })

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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