Реагируйте крюками с Гэтсби. onClick меняет setState на второй Click только - PullRequest
1 голос
/ 13 октября 2019

Я создаю персональный сайт, где у меня есть куча стилизованных карт, рендеринг с помощью карты массива, созданного с помощью запроса GraphQL.

Эти карты имеют тег, и моя цель в том, чтобы, когда выщелкните по указанному тегу, он отфильтрует исходный массив, оставив только элементы, включающие тег.

Идет что-то вроде этого


const Tutoriales = ()=> {




    const blog = useStaticQuery(graphql`
    query {
        allMarkdownRemark (
          sort: {fields: frontmatter___date, order: DESC}

         )


        {
            edges {
                node { 
                    frontmatter {
                        title,
                        date,
                        type,
                        abs,
                        tag,
                        featuredImage {
                            relativePath,
                            absolutePath,
                            childImageSharp{
                                fixed(width: 300) {
                                    ...GatsbyImageSharpFixed
                                }
                            }
                        }

                    }
                    html,
                    excerpt,
                    fields {
                        slug
                    }
                }
            }
        }
    }
    `
    );


    let pijon = blog.allMarkdownRemark.edges;
    const [cards, setCards] = useState(pijon);
    const [filter, setFilter] = useState("");

 return (
<div>

{
            cards.map((edge)=> {

 <Card className={classes.card}>
      <CardHeader
                      avatar={
                        <Avatar aria-label="Recipe" className={classes.avatar}>
                          {edge.node.frontmatter.type}
                        </Avatar>
                      }

                      title={<Link className={center.nodecor} to={url}>{edge.node.frontmatter.title}</Link>}
                      subheader={<Link className={center.nodecor} to={url}>{edge.node.frontmatter.date} </Link>}

                    />

 // This is my tag DIV, Im trying to make it work so that when you click
 // on the div, it will use the Filter Hook, to filter the card array


 <div onClick={ () => {
            setFilter(edge.node.frontmatter.tag);


            console.log(filter)
            let filteredCards = cards.filter((card) => {
              return card.node.frontmatter.tag === filter
            }

            )
          setCards(filteredCards);

        }

        }
           className={center.right}>
              {edge.node.frontmatter.tag}  </div>
          </div>


 </Card>

    )
            })
            }

</div>

    )
}

export default Tutoriales



Ожидаемый результат будет, что крючок карты будет теперьотфильтрованы для создания всех карт, которые не содержат тег, выбранный для исчезновения.

Но при этом все, что я получаю, это пустой массив. Я знаю, что это как-то связано с асинхронным хуком setState, и я читал об UseEffect, но не могу заставить его работать.

Используя console.log, я смог понять, что тольково второй раз, когда я щелкаю тег (со значением onClick), он работает.

Любой комментарий приветствуется.

1 Ответ

0 голосов
/ 13 октября 2019

Вы правы, это происходит, потому что setState вызовы являются пакетными. Поэтому, если вы вызываете setFilter и начинаете использовать filter в том же блоке, вы фактически используете его предыдущее значение. Вот почему он работает во второй раз.

setFilter(edge.node.frontmatter.tag);
console.log(filter);    <- filter has not actually changed yet

Самое простое исправление - удалить const [filter, setFilter] = useState(""); и просто использовать выбранный вами фильтр:

<div 
  onClick={() => {
    const filter = edge.node.frontmatter.tag;
    let filteredCards = cards.filter((card) => {
      return card.node.frontmatter.tag === filter
    });
    setCards(filteredCards);
  }}
  className={center.right}
>
    {edge.node.frontmatter.tag}
</div>

Другое решение заключается в использовании хука useEffect и обновлении карт после изменения filter:

const [cards, setCards] = useState(pijon);
const [filter, setFilter] = useState("");
useEffect(() => {
  if (filter) {  // don't do anyhiting when filter is empty on initial render
    const filteredCards = cards.filter((card) => {
      return card.node.frontmatter.tag === filter
    }
    setCards(filteredCards);
  }
}, [filter, setCards]);

// ...

<div 
  onClick={() => {setFilter(edge.node.frontmatter.tag);}}
  className={center.right}
>
    {edge.node.frontmatter.tag}
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...