这是我的代码:https://codesandbox.io/s/gatsby-starter-default-og782
逻辑很简单:我将Gatsby.js与React一起使用来渲染<StaticQuery
query={graphql`
{
allFile(
filter: {
extension: { regex: "/(jpg)|(jpeg)|(png)/" }
sourceInstanceName: { eq: "images" }
}
) {
edges {
node {
childImageSharp {
fluid(maxWidth: 800, quality: 95) {
aspectRatio
src
srcSet
originalName
srcWebp
srcSetWebp
sizes
}
}
}
}
}
}
`}
render={data => (
<Layout>
<Gallery minWidth={200} data={data.allFile.edges} />
</Layout>
)}
/>
组件
Gallery
这将为Gallery
提供图像文件以供显示。
在 const [allPics, setAllPics] = useState([]) <-- storing all the image files
const [currentImgs, setCurrentImgs] = useState([]) <-- storing the images of the current tab
const [tabs, setTabs] = useState([])
内部,我处于这些状态
useEffect
useEffect(() => {
const allPics = data.map((img, i) => {
img.node.childImageSharp.index = i
return img.node.childImageSharp
})
setAllPics(allPics)
setTabs(getAllTabs(allPics))
// default tab when the page first loads
setCurrentImgs(
allPics.filter(({ fluid }) => fluid.originalName.includes(tabs[0]))
)
}, [data])
仅在组件安装后运行一次
<>
<ProjectsContainer>
{tabs.map(tab => (
<Project
key={tab}
onClick={() => {
setCurrentImgs(
allPics.filter(({ fluid }) => fluid.originalName.includes(tab))
)
}}
>
{tab}
</Project>
))}
</ProjectsContainer>
<Mansory gap={"0em"} minWidth={minWidth}>
{currentImgs.map((img, i) => {
return (
<PicContainer
index={img.index}
selected={isSelected}
key={img.index}
>
<Enlarger
src={img.fluid.srcSet.split(" ")[0]}
enlargedSrc={img.fluid.src}
index={img.index}
setIsSelected={setIsSelected}
onLoad={() => {
setTimeout(() => {
refs[img.index].current.toggleOpacity(1)
}, 300)
}}
ref={refs[img.index]}
realIndex={i}
/>
</PicContainer>
)
})}
</Mansory>
</>
然后我以此渲染
currentImgs
问题是,状态useEffect
似乎仍然是一个空数组,这是setCurrentImgs
运行后的默认状态,因此,当我们第一次加载页面时,没有当前图像可显示。您必须手动单击任何这些选项卡才能再次触发useEffect
以显示当前图像。
所以问题似乎很明显,这就是为什么在currentImgs
和{{1}之类的其他状态下,allPics
中只有状态tabs
未正确设置}是否设置正确?
答案 0 :(得分:1)
此初始状态加载不需要使用useEffect
。您可以在useState
挂钩中设置状态的初始值,如下所示:
const [allPics, setAllPics] = useState(
data.map((img, i) => {
img.node.childImageSharp.index = i
return img.node.childImageSharp
})
)
const getAllTabs = imageObj => {
return imageObj
.map(({ fluid }) => fluid.originalName.split("-")[0])
.filter((name, index, self) => index === self.indexOf(name))
}
const [tabs, setTabs] = useState(getAllTabs(allPics))
const [currentImgs, setCurrentImgs] = useState(
allPics.filter(({ fluid }) => fluid.originalName.includes(tabs[0]))
)
您可以通过这些更改here看到沙盒的工作分支。
答案 1 :(得分:1)
类似于基于类的React组件的生命周期方法,特别是setState
的异步特性,功能对等useState
钩子也是如此。在当前渲染周期中,挂钩的当前值保持静态,直到“刷新”更新并重新渲染组件。在useEffect
钩子中,您尝试访问尚未“同步”的tabs
状态值。如果要在此渲染周期中使用该值,则应该直接访问tabs响应数组。
useEffect(() => {
const allPics = data.map((img, i) => {
img.node.childImageSharp.index = i
return img.node.childImageSharp
})
setAllPics(allPics)
// get all tabs
const tabsArray = getAllTabs(allPics);
setTabs(tabsArray)
// default tab when the page first loads
setCurrentImgs(
allPics.filter(({ fluid }) => fluid.originalName.includes(tabsArray[0]))
)
}, []) // pass empty dependency array if you truly only want this to run on mount
答案 2 :(得分:0)
React useEffect使用会话直到每次更新/或者我们可以说生命周期直到更改。 只需从useState挂钩传递useEffect中的参数,它将更新数据,
不要尝试传递数据变量,它将运行无限循环。只需传递setData函数即可。
React.useEffect(()=>{
console.log("effect");
(async () => {
try {
let result = await fetch("/query/countries");
const res = await result.json();
let result1 = await fetch("/query/projects");
const res1 = await result1.json();
let result11 = await fetch("/query/regions");
const res11 = await result11.json();
setData({countries: res, projects: res1, regions: res11});
} catch {
}
})()
}, [setData])