Как отобразить вложенный массив в gatsby с помощью reactjs и graphql

У меня есть компонент 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>
    }
  }
}

person Leniakea    schedule 15.09.2019    source источник


Ответы (1)


Вы должны иметь возможность использовать что-то похожее на метод вашей категории:

items = tempItems.filter(({ node }) =>
  node.tag.map(tag => tag.title).includes("tag2")
);

Поскольку это не обязательно конкретно для React / Gatsby, вот только данные и эти методы:

const data = {
  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"
            }]
          }
        }
      ]
    }
  }
};

let items = data.data.menu.edges.filter(
  ({
    node
  }) => node.category.title === "cat2"
);

console.log(items);

items = data.data.menu.edges.filter(({
    node
  }) =>
  node.tag.map(tag => tag.title).includes("tag2")
);

console.log(items);

person skovy    schedule 15.09.2019