如何使用reactjs和graphql在gatsby中映射嵌套数组

时间:2019-09-15 01:37:11

标签: arrays reactjs graphql gatsby strapi

我有一个menu.js组件,我将其导入页面以生成文章列表,可以按类别对其进行过滤。效果很好。

现在,我想更改组件,以便可以按标签过滤文章。问题在于标签是graphql中的嵌套数组,我无法使用映射类别的相同map()函数来访问。

我试图做一个嵌套的map函数,但是我无法使其工作,但是我怀疑这是解决方案。我的目标是拥有相同的功能,使我可以按标签而不是按类别过滤文章。我希望那是可能的。我正在使用带有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>
    }
  }
}

1 个答案:

答案 0 :(得分: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);