У меня есть компонент menu.js, который я импортирую на страницу для создания списка статей, которые можно фильтровать по категориям. Это прекрасно работает.
Теперь я хочу изменить компонент, чтобы можно было фильтровать статьи по тегам. Проблема в том, что теги представляют собой вложенный массив в graphql, которого я не могу достичь с помощью той же функции map (), которая отображает категории.
Я попытался выполнить функцию вложенной карты, но не могу заставить ее работать, но я подозреваю, что это решение. Моя цель - иметь ту же функциональность, где я могу фильтровать статьи по тегам, а не по категориям. Я надеюсь, что это возможно. Я использую Gatsby с серверной частью Strapi. Любые намеки в правильном направлении приветствуются :-)
/src/pages/articles.js
import graphql from 'gatsby'
import React from 'react'
import Layout from 'components/layout'
import MenuBlog from 'components/menublog'
const BlogPage = ({ data }) => (
<Layout>
<MenuBlog items={data.menu} />
</Layout>
)
export default BlogPage
export const pageQuery = graphql`
query BlogQuery {
menu: allStrapiArticle {
edges {
node {
id
title
slug
tag {
title
id
}
category {
title
id
}
}
}
}
}
`
Это то, что я получил из запроса GraphQL выше, каждая статья, конечно, может иметь один или несколько тегов, но назначена только одна категория.
{
"data": {
"menu": {
"edges": [
{
"node": {
"title": "articleName 1",
"slug": "articleName-1",
"category": {
"title": "cat1"
},
"tag": [
{
"title": "tag1"
},
{
"title": "tag2"
},
{
"title": "tag3"
}
]
}
},
{
"node": {
"title": "articleName 2",
"slug": "articleName-2",
"category": {
"title": "cat2"
},
"tag": [
{
"title": "tag3"
}
]
}
}
]
}
}
}
А вот и мой компонент, который отображает статьи по выбранной категории.
/src/components/menublog/index.js
import React, { Component } from 'react'
import { Link } from 'gatsby'
import Row from 'react-bootstrap/Row'
const getCategories = items => {
let tempItems = items.map(items => {
return items.node.category.title
})
let tempCategories = new Set(tempItems)
let categories = Array.from(tempCategories)
categories = ['all', ...categories]
return categories
}
export default class MenuBlog extends Component {
constructor(props) {
super(props)
this.state = {
items: props.items.edges,
articles: props.items.edges,
categories: getCategories(props.items.edges),
}
}
handleItems = category => {
let tempItems = [...this.state.items]
if (category === 'all') {
this.setState(() => {
return { articles: tempItems }
})
} else {
let items = tempItems.filter(
({ node }) => node.category.title === category
)
this.setState(() => {
return { articles: items }
})
}
}
render() {
if (this.state.items.length > 0) {
return (
<Row>
{/* items */}
<div className="col-md-8 blog-main bg-light">
<h1>Artikler</h1>
{this.state.articles.map(({ node }) => {
return (
<div key={node.id} className="blog-post mb-4">
<h2>
<Link to={`/artikler/${node.slug}`}>{node.title}</Link>
</h2>
{/* item text */}
</div>
)
})}
</div>
{/* categories */}
<div className="col-md-4 blog-sidebar">
<div className="p-4 mb-3 bg-light">
<h4>Kategorier</h4>
<ol className="list-unstyled mb-0">
{this.state.categories.map((category, index) => {
return (
<li key={index}>
<button
type="button"
className="btn"
onClick={() => {
this.handleItems(category)
}}
>
{category}
</button>
</li>
)
})}
</ol>
</div>
<div className="p-4 mb-3 bg-light">
<h4>Kategorier</h4>
</div>
</div>
</Row>
)
} else {
return <h1>no items</h1>
}
}
}