![](/img/trans.png)
[英]Using React Hooks, using "useState" and "useEffect", is there a way to render a state waiting till the state has a value?
[英]React Hooks: using useState inside useEffect doesn't set the state immediately after first rendering
這是我的代碼: 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]))
)
您可以在此處查看帶有這些更改的沙箱的工作分支。
就像基於類的useState
組件的生命周期方法一樣,特別是setState
的異步性質,函數對應物useState
鈎子也是useState
。 鈎子的當前值在當前渲染周期中保持靜態,直到更新被“刷新”並重新渲染組件。 在您的useEffect
鈎子中,您試圖訪問尚未“同步”的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
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])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.