React 与 Gatsby 挂钩。 onClick 仅在第二次单击时更改 setState
React hooks with Gatsby. onClick changes setState on second Click only
我正在制作一个个人网站,其中我有一堆程式化的卡片通过使用 GraphQL 查询创建的数组映射呈现。
那些卡片有一个标签,我的objective是当你点击这个标签时,它会过滤掉原来的数组,只留下包含标签的项目。
像这样
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 值)时它才有效。
如有任何意见,我们将不胜感激。
你是对的,发生这种情况是因为 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>
我正在制作一个个人网站,其中我有一堆程式化的卡片通过使用 GraphQL 查询创建的数组映射呈现。
那些卡片有一个标签,我的objective是当你点击这个标签时,它会过滤掉原来的数组,只留下包含标签的项目。
像这样
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 值)时它才有效。
如有任何意见,我们将不胜感激。
你是对的,发生这种情况是因为 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>