首页 > 解决方案 > 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设置不正确,而其他状态喜欢allPicstabs设置正确?

标签: javascriptreactjsfrontendgatsby

解决方案


您不需要使用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]))
)

您可以在此处查看具有这些更改的沙箱的工作分支。


推荐阅读