I want to execute "fetchPostData" and "setPost" which are inside "useLayoutEffect" before first rendering.
function PostViewPage() {
const { postId } = useParams();
const [post, setPost] = useState({});
const fetchPostData = async () => {
const postRawData = await callPostUrl(postId);
return postRawData.data;
};
useLayoutEffect(() => {
fetchPostData().then((res) => {
setPost(res);
});
}, []);
return (
<Wrapper>
<PageHeader
pageTitle="게시글"
rightButton={<img src={Menu} alt="img" />}
/>
<ViewCard key={postId} type={"full"} post={post} postId={postId} />
</Wrapper>
);
}
I've read that useLayoutEffect is executed before layout unlike useEffect, but still, state named "post"(which is changed by "setPost") are changed at second rendering.
This is the problem because I want to give "post" to the component named "ViewCard" as props. And ViewCard use "~.map" function using "post". Because there's nothing given to the "post" at first render, "ViewCard" returns error.
Cannot read properties of undefined (reading 'map')
, which means there are no data in "post".
Second rendering aren't being executed because of the error in first rendering.
I think "post" should be changed at the time the components are returned. What I mean is, isn't "post" should be changed at first rendering?
I think "setPost" is making rerender when I read this article. https://jsramblings.com/are-you-logging-the-state-immediately-after-updating-it-heres-why-that-doesnt-work/
Then how can I give state to components at the first render? Please help me.
Thank you.
CodePudding user response:
So, even if "useLayoutEffect is executed before layout unlike useEffect", you are doing an api request. And it takes time. There is nothing in the code that stops the view from being rendered while your request is pending.
Wha you can do here is to stop view from being renders while there is nothing in the post state.
const [post, setPost] = useState(null)
...
useEffect(... your api request logic here and setPost(...) the response, [...])
if (!post) return null
return (...view)
CodePudding user response:
one solution is to check :
if (JSON.stringify(post) === '{}') {
return <div> Loading... </div>
} else {
return (
<Wrapper>
<PageHeader
pageTitle="게시글"
rightButton={<img src={Menu} alt="img" />}
/>
<ViewCard key={postId} type={"full"} post={post} postId={postId} />
</Wrapper>)
}
the only two methods that can be called before the first render are constructor()
and getDerivedStateFromProps()
learn more here about react component life cycle