Search code examples
reactjsif-statementuse-statefetching-strategy

Fetching with if statements - Conditional Fetching Problems


The app I am working on allows users to connect social media integrations facebook, instagram, and youtube, into my app. Once connected it pulls all of their posts from those services and puts it into one place - my app.

For example... the user can solely connect facebook. Or the user can connect all three.

The problem is if they connect all three, my newest integration (youtube) doesn't add the posts to the page. I beleive its because of how I am storing the posts - in React State.

My code below does the following.. It fetches the native posts to my platform. Then if the user has youtube connected, it fetches the youtube posts and adds them to the native posts. After this I have another if/else statement that says if the user has connected facebook or instagram it fetches those posts, and adds them to the all the posts.

What happens is, if the user has connected all three, then the fetched youtube posts, which have been added, get overwritten with the new fb or instagram posts. - I am looking for recommendations on how to code this so that it still conditionally fetches the youtube posts, but doesn't overwrite them when its all over. I'll explain how it works in the comments in the code as well.

I guess I need to figure out how to get my youtube posts in a higher scope, so that they dont get overwritten.

Thanks!

 const getPosts = async () => {
    const token = await getTokenSilently();

    try {
        //Get ODB/Native Posts
        let response = await fetch(`/api/autoquotegenerators/${_id}`, {
            headers: {
                Authorization: `bearer ${token}`,
                "Content-Type": "application/json; charset=UTF-8",
            }
        });
        const responseData = await response.json()
        setBand(responseData)
        setYoutube(responseData.youtube)
        setFavorites(responseData.favorites)
        setFbData(responseData.fbData)
        setGoogleData(responseData.googleData)
        if(!responseData.fbData){
            setPosts(responseData.posts)
        }

        //Get New Youtube Posts if the user connects Youtube.
        if(responseData.googleData){
            let apiKey = process.env.REACT_APP_GOOGLE_API

            //Get Youtube Uploads Playlist Id
            let response = await fetch(`https://www.googleapis.com/youtube/v3/channels?part=contentDetails&id=${responseData.googleData.channelId}&key=${apiKey}`)
            let playlistIdResponse = await response.json()
            let uploadsPlayListId = playlistIdResponse.items[0].contentDetails.relatedPlaylists.uploads

            //Get Videos from Uploads Playlist
            response = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?playlistId=${uploadsPlayListId}&key=${apiKey}&part=snippet&maxResults=50`)
            let videosResponse = await response.json()

            //Create Youtube Posts
            let youtubeFormattedPosts = []
            videosResponse.items.forEach(video => {
                let youtubeVideoObject = {
                    type: "video", 
                    data: video.snippet.resourceId.videoId, 
                    date: video.snippet.publishedAt, 
                    postId: video.id, 
                    rockOn: []
                }
                youtubeFormattedPosts.push(youtubeVideoObject)
            })

            //Set All Posts - This works, if no other apis get called.
            setPosts([ 
                ...responseData.posts, 
                ...youtubeFormattedPosts
                    .filter(({postId}) => 
                    !responseData.posts
                        .find(post => post.postId == postId)),
            ])
        }

        let fbDataTemp = responseData.fbData
        if(responseData.fbData && !responseData.fbData.instaId){
            //Get Only FB and ODB Posts
            //Get Fb Posts
            let fbFormattedPosts = []
            response = await fetch(`https://graph.facebook.com/${fbDataTemp.pageId}/feed?access_token=${fbDataTemp.pageAccessTokenLong}`)
            let fbPosts = await response.json()
            fbPosts.data.forEach(post => {
                if(post.message){
                    let fbPostObject = {
                        type: 'text',
                        data: post.message,
                        link: `http://www.facebook.com/${post.id}`,
                        date: post.created_time.slice(0, -2) + ':' + post.created_time.slice(-2),
                        postId: post.id,
                        rockOn: []
                    }
                    fbFormattedPosts.push(fbPostObject)
                }
            })

            //Set All Posts 
            setPosts([ 
                ...responseData.posts, 
                ...fbFormattedPosts
                    .filter(({postId}) => 
                    !responseData.posts
                        .find(post => post.postId == postId)),
            ])

        }else if(responseData.fbData && responseData.fbData.instaId){
            //First Get Fb Posts
            let fbFormattedPosts = []
            response = await fetch(`https://graph.facebook.com/${fbDataTemp.pageId}/feed?access_token=${fbDataTemp.pageAccessTokenLong}`)
            let fbPosts = await response.json()
            fbPosts.data.forEach(post => {
                if(post.message){
                    let fbPostObject = {
                        type: 'text',
                        data: post.message,
                        link: `http://www.facebook.com/${post.id}`,
                        date: post.created_time.slice(0, -2) + ':' + post.created_time.slice(-2),
                        postId: post.id,
                        rockOn: []
                    }
                    fbFormattedPosts.push(fbPostObject)
                }
            })

            //Get IG Media Ids 
            let instaFormattedPosts = []
            response = await fetch(`https://graph.facebook.com/v7.0/${fbDataTemp.instaId}/media?access_token=${fbDataTemp.pageAccessTokenLong}`)
            let instaPosts = await response.json()

            //Get IG Posts 
            for (let i=0 ; i< instaPosts.data.length ; i++) {
                const instaId = instaPosts.data[i];
                const instaResponse = await fetch(`https://graph.facebook.com/${instaId.id}?fields=id,media_url,timestamp,username&access_token=${fbDataTemp.pageAccessTokenLong}`)
                let instaPostRendered = await instaResponse.json()

                let instaPostObject = {
                    type: 'instagram',
                    data: instaPostRendered.media_url,
                    link: `http://www.instagram.com/${instaPostRendered.username}`,
                    date: instaPostRendered.timestamp,
                    postId: instaPostRendered.id,
                    rockOn: [],
                }
                instaFormattedPosts.push(instaPostObject)
            }

            //Set All Posts 
            setPosts([ 
                ...responseData.posts, 
                ...fbFormattedPosts
                .filter(({postId}) => 
                    !responseData.posts
                        .find(post => post.postId == postId)),
            ...instaFormattedPosts
                    .filter(({postId}) => 
                            !responseData.posts
                                .find(post => post.postId == postId))
            ])
        }
    } catch (error) {
        console.log(error)
    }
}

I guess the way I am thinking of fixing this is to using var instead of let to define the arrays that hold the posts after fetching. Then just setting AllPosts at once?


Solution

  • Since you have multiple setState calls being executed in the function, hence certain fields get overriden

    The solution is to save all the posts in a variable and trigger setPosts once in the end of the function

    const getPosts = async () => {
        const token = await getTokenSilently();
    
        try {
            //Get ODB/Native Posts
            let response = await fetch(`/api/autoquotegenerators/${_id}`, {
                headers: {
                    Authorization: `bearer ${token}`,
                    "Content-Type": "application/json; charset=UTF-8",
                }
            });
            const responseData = await response.json()
            setBand(responseData)
            setYoutube(responseData.youtube)
            setFavorites(responseData.favorites)
            setFbData(responseData.fbData)
            setGoogleData(responseData.googleData);
            let newPosts = [];
            if(!responseData.fbData){
                newPosts = responseData.posts;
            }
    
            //Get New Youtube Posts if the user connects Youtube.
            if(responseData.googleData){
                let apiKey = process.env.REACT_APP_GOOGLE_API
    
                //Get Youtube Uploads Playlist Id
                let response = await fetch(`https://www.googleapis.com/youtube/v3/channels?part=contentDetails&id=${responseData.googleData.channelId}&key=${apiKey}`)
                let playlistIdResponse = await response.json()
                let uploadsPlayListId = playlistIdResponse.items[0].contentDetails.relatedPlaylists.uploads
    
                //Get Videos from Uploads Playlist
                response = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?playlistId=${uploadsPlayListId}&key=${apiKey}&part=snippet&maxResults=50`)
                let videosResponse = await response.json()
    
                //Create Youtube Posts
                let youtubeFormattedPosts = []
                videosResponse.items.forEach(video => {
                    let youtubeVideoObject = {
                        type: "video", 
                        data: video.snippet.resourceId.videoId, 
                        date: video.snippet.publishedAt, 
                        postId: video.id, 
                        rockOn: []
                    }
                    youtubeFormattedPosts.push(youtubeVideoObject)
                })
    
                //Set All Posts - This works, if no other apis get called.
                newPosts = [ 
                    ...responseData.posts, 
                    ...youtubeFormattedPosts
                        .filter(({postId}) => 
                        !responseData.posts
                            .find(post => post.postId == postId)),
                ];
            }
    
            let fbDataTemp = responseData.fbData
            if(responseData.fbData && !responseData.fbData.instaId){
                //Get Only FB and ODB Posts
                //Get Fb Posts
                let fbFormattedPosts = []
                response = await fetch(`https://graph.facebook.com/${fbDataTemp.pageId}/feed?access_token=${fbDataTemp.pageAccessTokenLong}`)
                let fbPosts = await response.json()
                fbPosts.data.forEach(post => {
                    if(post.message){
                        let fbPostObject = {
                            type: 'text',
                            data: post.message,
                            link: `http://www.facebook.com/${post.id}`,
                            date: post.created_time.slice(0, -2) + ':' + post.created_time.slice(-2),
                            postId: post.id,
                            rockOn: []
                        }
                        fbFormattedPosts.push(fbPostObject)
                    }
                })
    
                //Set All Posts 
                newPosts = [ 
                    ...newPosts, 
                    ...fbFormattedPosts
                        .filter(({postId}) => 
                        !newPosts
                            .find(post => post.postId == postId)),
                ]
    
            }else if(responseData.fbData && responseData.fbData.instaId){
                //First Get Fb Posts
                let fbFormattedPosts = []
                response = await fetch(`https://graph.facebook.com/${fbDataTemp.pageId}/feed?access_token=${fbDataTemp.pageAccessTokenLong}`)
                let fbPosts = await response.json()
                fbPosts.data.forEach(post => {
                    if(post.message){
                        let fbPostObject = {
                            type: 'text',
                            data: post.message,
                            link: `http://www.facebook.com/${post.id}`,
                            date: post.created_time.slice(0, -2) + ':' + post.created_time.slice(-2),
                            postId: post.id,
                            rockOn: []
                        }
                        fbFormattedPosts.push(fbPostObject)
                    }
                })
    
                //Get IG Media Ids 
                let instaFormattedPosts = []
                response = await fetch(`https://graph.facebook.com/v7.0/${fbDataTemp.instaId}/media?access_token=${fbDataTemp.pageAccessTokenLong}`)
                let instaPosts = await response.json()
    
                //Get IG Posts 
                for (let i=0 ; i< instaPosts.data.length ; i++) {
                    const instaId = instaPosts.data[i];
                    const instaResponse = await fetch(`https://graph.facebook.com/${instaId.id}?fields=id,media_url,timestamp,username&access_token=${fbDataTemp.pageAccessTokenLong}`)
                    let instaPostRendered = await instaResponse.json()
    
                    let instaPostObject = {
                        type: 'instagram',
                        data: instaPostRendered.media_url,
                        link: `http://www.instagram.com/${instaPostRendered.username}`,
                        date: instaPostRendered.timestamp,
                        postId: instaPostRendered.id,
                        rockOn: [],
                    }
                    instaFormattedPosts.push(instaPostObject)
                }
    
                //Set All Posts 
                newPosts = [ 
                    ...newPosts, 
                    ...instaFormattedPosts
                        .filter(({postId}) => 
                                !newPosts
                                    .find(post => post.postId == postId))
                ];
    
            }
    
            setPosts(newPosts);
        } catch (error) {
            console.log(error)
        }
    }