'Duplicate of doc data created when trying to retrieve document data from firestore database in firebase

I've been tackling this issue for some days now but to no avail. I stored some images and other descriptions related to the images in my firestore database. But each time I try to retrieve the data from the database, it duplicates all the documents and then displays all the images twice after.

import React, {useEffect, useState} from 'react';
import styled from 'styled-components';
import { useParams } from 'react-router-dom';
import { getDoc, doc, onSnapshot } from 'firebase/firestore';
import db from '../firebase';

const Detail = () => {

    const {id} = useParams();
    const [detailData, setDetailData] = useState([]);

    useEffect(() => {
        
        // const getData = async () => {
            
        //     const movieRef = doc(db, "movies", id);
            
        //     try {
        //         setDetailData([]);
        //         const doc = await getDoc(movieRef);
        //         setDetailData(doc.data());
        //         console.log(detailData);
        //         return;
        //     } catch (e) {
        //         alert("Error getting cached document:", e);
        //     }
        //     };
        //     getData();

             const docRef = doc(db, "movies", id);
                onSnapshot(docRef, (doc) => {
                    if(doc.exists){
                        setDetailData(doc.data());
                        console.log(detailData);
                    } else{
                        console.log("no such document in firebase");
                    }
                })
    }, [id]);

  return (

    <Container>
        <Background>
            <img src={detailData.backgroundImg} alt={detailData.title} />
        </Background>

        <ImageTitle>
            <img src={detailData.titleImg} alt={detailData.title} />
        </ImageTitle>

        <ContentMeta>

            <Controls>

                <Player>
                    <img src="/images/play-icon-black.png" alt="play button" />
                    <span>Play</span>
                </Player>

                <Trailer>
                    <img src="/images/play-icon-white.png" alt="trailer button" />
                    <span>Trailer</span>
                </Trailer>

                <AddList>
                    <span/>
                    <span/>
                </AddList>

                <GroupWatch>
                    <div>
                        <img src="/images/group-icon.png" alt="group icon" />
                    </div>
                </GroupWatch>

            </Controls>

            <SubTitles>
                {detailData.subTitle || 'Subtitles'}
            </SubTitles>

            <Description>
                {detailData.description ||'Description'}
            </Description>
        </ContentMeta>

    </Container>

  );

}

const Container = styled.div`
    position: relative;
    min-height: calc(100vh - 250px);
    overflow-x: hidden;
    display: block;
    top: 72px;
    padding: 0 calc(3.5vw + 5px);

`;

const Background = styled.div`
    left: 0px;
    opacity: 0.8;
    position: fixed;
    right: 0px;
    top: 0px;
    z-index: -1;

    img{
        width: 100vw;
        height: 100vh;

         /* @media (max-width: 768px) {
            object-fit: cover; 
             width: initial;
        }   */
    }
`;

const ImageTitle = styled.div`
    display: flex;
    align-items: flex-end;
    -webkit-box-pack: start;
    justify-content: flex-start;
    margin: 0px auto;
    height: 30vw;
    min-height: 170px;
    padding-bottom: 24px;
    width: 100%;

    img{
        max-width: 600px;
        min-width: 200px;
        width: 35vw;

    }
`;

const ContentMeta = styled.div`
    max-width: 874px;
`;

const Controls = styled.div`
    align-items: center;
    display: flex;
    flex-flow: row nowrap;
    margin: 24px 0px;
    min-height: 56px;

`;

const Player = styled.button`
    font-size: 15px;
    margin: 0px 22px 0px 0px;
    padding: 0px 24px;
    height: 56px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    cursor: pointer;
    justify-content: center;
    letter-spacing: 1.8px;
    text-align: center;
    text-transform: uppercase;
    background: rgb(249, 249, 249);
    border: none;
    color: rgb(0, 0, 0);

    img{
        width: 32px;
    }

    &:hover{
        background: rgb(198, 198, 198);
    }

    @media (max-width: 768px){
        height: 45px;
        padding: 0px 12px;
        font-size: 12px;
        margin: 0px 10px 0px 0px;

        img{
            width: 25px;
        }
    }
`;

const Trailer = styled(Player)`
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid rgb(249, 249, 249);
    color: rgb(249, 249, 249);
`;

const AddList = styled.div`
    margin-right: 16px;
    height: 44px;
    width: 44px;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgba(0, 0, 0, 0.6);
    border-radius: 50%;
    border: 2px solid white;
    cursor: pointer;

    span{
        background-color: rgb(249, 249, 249);
        display: inline-block;

        &:first-child{
            height: 2px;
            transform: translate(1px, 0px) rotate(0deg);
            width: 16px;
        }

        &:nth-child(2){
            height: 16px;
            transform: translateX(-8px) rotate(0deg);
            width: 2px;
        }
    }
`;

const GroupWatch = styled.div`
    height: 44px;
    width: 44px;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    background: white;

    div{
        height: 40px;
        width: 40px;
        background: rgb(0, 0, 0);
        border-radius: 50%;

        img{
            width: 100%;
        }
    }
`;

const SubTitles = styled.div`
    color: rgb(249, 249, 249);
    font-size: 15px;
    min-height: 20px;

    @media (max-width:768px) {
        font-size: 12px;
    }
`;

const Description = styled.div`
    line-height: 1.4;
    font-size: 20px;
    padding: 16px 0px;
    color: rgb(249, 249, 249);

    @media (max-width: 768px) {
        font-size: 14px;
    }
`;

export default Detail;

Now, the images contained inside this Trending row and other similar movie rows all get displayed twice when I go back to the home page:

import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { selectTrending } from '../features/movie/movieSlice';

const Trending = (props) => {

  const movies = useSelector(selectTrending);

  return (

    <Container>
        <h4>Trending</h4>

        <Content>

            {
                movies && movies.map((movie, key) => (
                    <Wrap key={key}>
                        {movie.id}
                        <Link to={`/detail/` + movie.id}>
                            <img src={movie.cardImg} alt={movie.title} />      
                        </Link>
                    </Wrap>
                ))
            }

        </Content>

    </Container>

  )

};

const Container = styled.div`
    padding: 0 0 26px;
`;

const Content = styled.div`
    display: grid;
    grid-gap: 25px;
    gap: 25px;
    grid-template-columns: repeat(4, minmax(0, 1fr));

    @media (max-width: 768px){
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
`;

const Wrap = styled.div`
    padding-top: 56.25%;
    border-radius: 10px;
    box-shadow: rgb(0 0 0 / 69%) 0px 26px 30px -10px,
        rgb(0 0 0 / 73%) 0px 16px 10px 10px;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    transition: all 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94) 0s;
    border: 3px solid rgba(249, 249, 249, 0.1);

    img{
        inset: 0px;
        display: block;
        height: 100%;
        object-fit: cover;
        opacity: 1;
        position: absolute;
        transition: opacity 500ms ease-in-out 0s;
        width: 100%;
        z-index: 1;
        top: 0;
    }

    &:hover{
        box-shadow: rgb(0 0 0 / 80%) 0px 40px 58px -16px,
            rgb(0 0 0 / 72%) 0px 30px 22px -10px;
            transform: scale(1.05);
            border-color: rgba(249, 249, 249, 0.8);
    }
`;

export default Trending;


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source