user4181107
user4181107

Reputation: 401

How to update state without entering infinite re-render loop in React/Next.js?

I have a Next.js app that plays random YouTube videos. My state for the app looks something like this (in a Redux store):

const state = {
    entities: {
        videos: {
            'vidId1': {
                id: 'vidId1',
                title: 'Video 1'
            },
            'vidId2': {
                id: 'vidId2',
                title: 'Video 2'
            },
            'vidId3': {
                id: 'vidId3',
                title: 'Video 3'
            }
        }
    },
    uncategorized: {
        isFetching: false,
        hasNextPage: false,
        nextIndex: 0,
        items: [
            'vidId1',
            'vidId2',
            'vidId3'
        ]
    }
};

I then have my home page that looks something like the following:

// index.js
const Index = () => {
    return (
        <div>
            <h1>Home Page</h1>
            <RandomVideoButton />
        </div>
    );
};

The <RandomVideoButton /> links to /random. This page just gets the next video ID from the state and redirects to /videos?id={id}. It looks something like this:

// random.js
const RandomVideo = () => {
    // Get next video ID
    const nextVideoId = useSelector(state => state.uncategorized.items[state.uncategorized.nextIndex]);

    // Redirect to next video
    const router = useRouter();
    router.push({
        pathname: '/videos',
        query: { id: nextVideoId }
    });

    return (
        <div>Loading video...</div>
    );
};

Once I'm on /videos?id={id}, that page will load the video from state.entities.videos and it will then update state.uncategorized.nextIdnex. This is where the problem occurs. When I dispatch the action to update the next video index in the state, I get stuck in an infinite re-render loop. This is what watch.js looks like:

const WatchVideo = () => {
    // Get video ID from URL query
    const router = useRouter();
    const videoId = router.query.id;

    // Get video
    const { video, activeVideos } = useSelector(state => state.entities.videos[videoId]);

    // Update video index
    const dispatch = useDispatch();
    dispatch({ type: 'INCREMENT_NEXT_INDEX' });

    return (
        <div className="col-12 col-lg-8 col-xl-9">
            {video &&
                <main>
                    <div className="embed-responsive embed-responsive-16by9">
                        <iframe id="player" src={'https://www.youtube-nocookie.com/embed/' + video.id}></iframe>
                    </div>
                    <h1>{video.title}</h1>
                </main>
            }
        </div>
    );
};

My problem is I'm not sure how to prevent this from happening while still being able to update next video index in the state.

Upvotes: 0

Views: 1456

Answers (1)

Harish Dhami
Harish Dhami

Reputation: 1086

you should use dispatch/routing inside react useEffect hook. and you can use the videoId as a useEffect dependency.

Upvotes: 1

Related Questions