javascript - React Hooks:在 useEffect 中使用 useState 不会在第一次渲染后立即设置状态
问题描述
这是我的代码:https ://codesandbox.io/s/gatsby-starter-default-og782
逻辑很简单:我使用 Gatsby.js 和 React 来渲染一个Gallery
组件
<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
设置不正确,而其他状态喜欢allPics
和tabs
设置正确?
解决方案
您不需要使用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]))
)
您可以在此处查看具有这些更改的沙箱的工作分支。
推荐阅读
- machine-learning - Pytorch 中的自定义 LSTM 模型显示输入大小不匹配
- power-automate - 有没有办法在不查看仅运行用户的侧边栏菜单的情况下运行 MS 流程?
- spring - Eclipse STS 3.9.10:无法使用 SpringYamlEditor 读取 Yml 文件
- java - 将 Spring Boot 从 1.5.x 升级到 2.0.x 并出现 @Component 和 @Scope 注释错误
- javascript - React useEffect hook with warning react-hooks/exhaustive-deps
- azure-devops - 为 PR 触发构建,但在 PR 完成之前阻止 CD
- r - Small multiple maps with geom_sf at the same spatial scale
- c++ - Compiling header files for C++ using VSCode Code Runner
- angularjs - 将图像从前端应用程序保存到后端 API 的正确方法
- c# - Resizing GUI elements with form resize