#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
?