首页 > 解决方案 > 如何使用 reactjs 和 graphql 在 gatsby 中映射嵌套数组

问题描述

我有一个组件 menu.js,我将其导入页面以生成可以按类别过滤的文章列表。这完美地工作。

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

我试图做一个嵌套的地图功能,但我无法让它工作,但我怀疑这是解决方案。我的目标是拥有相同的功能,我可以按标签而不是按类别过滤文章。我希望那是可能的。我正在使用带有 Strapi 后端的 gatsby。任何正确方向的提示表示赞赏:-)

/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>
    }
  }
}

标签: arraysreactjsgraphqlgatsbystrapi

解决方案


您应该能够使用类似于您的类别方法的东西:

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);


推荐阅读