Гэтсби: Создание страниц из содержательных полей

#reactjs #gatsby #contentful

Вопрос:

У каждого из моих постов в Contentful есть несколько связанных с ним «категорий». Например, один пост может содержать:

 major: "HCD"
year: "1st Year"
tools: ["R", "Python", "Wordpress"]
 

Это просто поля , которые называются major и year т. Д. с этими значениями, но они рассматриваются как отдельные категории.
На веб — сайте они отображаются как таковые:
изображение

Я пытаюсь создать страницу для каждой из этих категорий. Например, если пользователь нажимает Photoshop , они должны быть перенесены на страницу tags/photoshop , и все сообщения, содержащие этот тег, должны быть перечислены.

К счастью, я смог найти это руководство, которое поможет мне в этом. Однако руководство предназначено не для содержательных данных, поэтому у меня возникли некоторые проблемы с тем, как это сделать. Я создал tagsTemplate.jsx и, но я застрял на создании реальных страниц.

Например, это то, что я сделал, чтобы попытаться создать страницы для tools :

Мой gatsby-node.js файл выглядит так:

 const path = require(`path`)
const _ = require('lodash');

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = `
    type contentfulPortfolioDescriptionTextNode implements Node {
      description: String
      major: String
      author: String
      tools: [String]
      files: [ContentfulAsset]
      contact: String
    }
    type ContentfulPortfolio implements Node {
      description: contentfulPortfolioDescriptionTextNode
      gallery: [ContentfulAsset]
      id: ID!
      name: String!
      related: [ContentfulPortfolio]
      slug: String!
      major: String!
      files: [ContentfulAsset]
      author: String!
      tools: [String]!
      year: String!
      thumbnail: ContentfulAsset
      url: String
      contact: String
    }
  `
  createTypes(typeDefs)
}

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions

  return new Promise((resolve, reject) => {
    graphql(`
      {
        portfolio: allContentfulPortfolio {
          nodes {
            slug
            tools
          }
        }
      }
    `).then(({ errors, data }) => {
      if (errors) {
        reject(errors)
      }

      if (data amp;amp; data.portfolio) {
        const component = path.resolve("./src/templates/portfolio-item.jsx")
        data.portfolio.nodes.map(({ slug }) => {
          createPage({
            path: `/${slug}`,
            component,
            context: { slug },
          })
        })
      }
       
      const tools = data.portfolio.nodes.tools;
      const tagTemplate = path.resolve(`src/templates/tagsTemplate.js`);
      let tags = [];
      // Iterate through each post, putting all found tags into `tags`
      tags = tags.concat(tools);
       // Eliminate duplicate tags
      tags = _.uniq(tags);
      
       // Make tag pages
       tags.forEach(tag => {
        createPage({
          path: `/tags/${_.kebabCase(tag)}/`,
          component: tagTemplate,
          context: {
            tag
          },
        });
      });
      
      console.log("Created Pages For"   tags)

      resolve()
    })
  })
}

 

Мой tagsTemplate сейчас минимальный, так как я не знаю, как запросить данные:

 import React from 'react';
import Layout from "../layouts/Layout"

const Tags = ({ data }) => {
  return (
    <Layout>
      <div>Tags</div>
    </Layout>
  );
};

export default Tags;

 

Проблема: Когда я посещаю страницу для одного из тегов, которые, как я знаю, существуют (например photoshop ), я получаю 404. Почему эти страницы не создаются?

Что я делаю не так и как я могу это исправить? Как это можно обобщить для трех моих «категорий»?

Комментарии:

1. Можете ли вы отладить свой tags массив?

2. @FerranBuireu Как мне это сделать? Я пытался console.log(tags) , но это показывает, как undefined . Это происходит во время сборки. Я не знаю, как впоследствии отлаживать отдельные переменные.

3. Тогда вы не сможете создавать страницы из undefined переменной. Что там внутри tools ?

4. @FerranBuireu, для каждого поста инструменты-это массив строк, таких как ["R", "Python", "Wordpress"] В верхней части моего поста приведен пример.

5. Ваш код выглядит хорошо, так tags как должен быть заполнен tools . Каковы результаты: tags.forEach(tag => {console.log(tag);createPage({path:`/tags/${_.kebabCase(tag)}/`,component: tagTemplate,context: {tag},});

Ответ №1:

Согласно тому, что вы сказали в комментариях:

Я пытался console.log(tags) , но это показывает, как undefined

Я сделал это, и это просто пустое место. Означает ли это, что внутри tags вообще ничего нет?

Ваша функция контакта выглядит хорошо, подход хорош, так как вы добавляете tools (список tags ) в новый массив, чтобы очистить его и оставить уникальные значения ( uniq ). После этого вы просматриваете уникальные теги и создаете страницы на основе этого массива.

Тем не менее, есть несколько слабых мест, где ваш карточный домик может развалиться. Ваша проблема начинается с этой строки:

 const tools = data.portfolio.nodes.tools;
 

И распространяется через код.

nodes является массивом, поэтому, чтобы получить любое значение, вы должны сделать:

 const tools = data.portfolio.nodes[0].tools;
 

Чтобы занять первую позицию и так далее…

Поскольку tools он никогда не заполняется, остальная часть кода не работает.

Вы можете легко исправить это, пройдя по циклу nodes и заполнив свой tags массив чем-то похожим на:

   const toolNodes = data.portfolio.nodes;

  const tagTemplate = path.resolve(`src/templates/tagsTemplate.js`);
  let tags = [];

  // Iterate through each post, putting all found tags into `tags`
  toolNodes.map(toolNode => tags.push(toolNode.tools);
  // if the fetched data is still an array you can do toolNodes.map(toolNode => tags.push(...toolNode.tools);     

   // Eliminate duplicate tags
  tags = _.uniq(tags);
  
   // Make tag pages
   tags.forEach(tag => {
    createPage({
      path: `/tags/${_.kebabCase(tag)}/`,
      component: tagTemplate,
      context: {
        tag
      },
    });
  });
  
  console.log("Created Pages For"   tags)
 

Комментарии:

1. Это работает! За исключением одной проблемы. Вместо того, чтобы создавать страницы для weaving и charcoal и web-design по отдельности , он создает страницы, подобные этой: http://localhost:8000/tags/weaving-charcoal-web-design/ , все в одном.

2. Если для остальных тегов работает, ваша структура данных отличается для каждой записи, и цикл не генерирует одну и ту же структуру массива (т. е. ["a", ["b","c","d"]] вместо ["a", "b", "c","d"] . Проверьте полученные данные или добавьте кодовое поле

3. В этом случае используйте toolNodes.map(toolNode => tags.push(...toolNode.tools);

4. Большое вам спасибо!! Это прекрасно работает. Если я могу задать последний вопрос на стороне, хранится ли этот tags массив глобально? Могу ли я сослаться на это на другой странице, чтобы перечислить все tools или это невозможно?

5. Кроме того, это работает только тогда, когда я инициализирую вызываемый пустой массив tools . Я предполагаю, что const toolNodes = data.portfolio.nodes; он содержит все узлы, так как же он разделяет тот, который называется tools ?