简体   繁体   中英

React setState() not setting state on certain items

I'm new to React and have some pretty simple code that is acting strange (I think).

The main app fetches a list of blog posts from a server, then passes them through props to a child component which spits the list out. By default, I'm trying to make the posts only show a preview like a title, and each post will have a state attached to it so I can keep track of which ones are fully shown or previewed.

I have the states set up like this:

const [posts, setPosts] = useState([])
const [postFullView, setPostFullView] = useState([])

The list initially is rendered as an empty list so nothing gets returned. When the data fetch finishes, it re-renders with all the posts.

I use useEffect for this in the child component:

    useEffect(() => {
        console.log('render')         //Just to verify this got called
        setPosts(props.posts)         //Logs empty array 3 lines down,
        //setPosts([4,5,6])           //Works fine, gets logged as [4,5,6]
        console.log(props.posts)      //Logs an array of 32 objects - so props is clearly not empty
        console.log(posts)            //Logs empty array as if setPosts did nothing, but logs [4,5,6] if I comment out setPosts(props.post) and use setPosts([4,5,6])

        setPostFullView(posts.map(post => {return {id: post.id, view: false}}))
        console.log(postFullView)     //Will be empty since posts is empty
    }, [props])

Hopefully, I explained clearly what I'm confused about - I can setState using a hard-coded array, but passing in props.posts does not do anything, even though it has content.

There is nothing wrong about your code, and the reason console.log(posts) spits empty array, it because setPosts(props.posts) is async call and not executed immediately, but tells react it should render again with new value for state.

Sometimes, like in your hardcoded array case, the code will work "fine", but it not guaranteed, for sure in production when code executed faster

yea its nothing wrong because the setState api is async did not show the changes in log but code is work properly and also if you need to check your state you can use React developer Tools extension for browser too see the state status https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en

Actually, your first issue is about understanding the state changing and the re-rendering on ReactJS. why you do not use the first initial state in the first render just like below:

const YourComponent = ({ posts: initialPosts }) => {
  const [posts, setPosts] = useState(initialPosts);

Also, there is no need to have the first line you can use it exactly on the second line initializing, like this:

const YourComponent = ({ posts: initialPosts }) => {
  const [postFullView, setPostFullView] = useState(
    ({ id }) => ({ id, view: false }) // es6 arrow function with using restructuring assignment and returning the object
  );

After all, when you are using a useEffect or other hooks APIs, please add the specific internal state or prop name to dependencies, no put all the props in the array of dependencies, it caused bad costs and make your project slow to run.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM