next.jsreact-reduxinfinite-loopredux-toolkitrerender

Redux toolkit + nextjs infinite rerender loop........ (I've read all the similar question.. no answer there...)


I have an infinite rerender loop on one of my pages. Seems like the same logic but with different slices works fine in other pages... But this one for some reason causes the infinite loop and the tab just freezes..... so:

  1. it seems like I tried everything
  2. moving the requests to the server and vice versa
  3. removing other reducers so the app would have only the one that causes the issue
  4. moving dependencies inside the useEffect dep array
  5. changing the state logic inside of the slices
  6. moving the page to the main page, so there would be no routing involved

and I guess smth else I don't remember already.... But nothing helped...((

so here's the code.

my localhost:3000/chat page when the problem occurs...:

'use client';
import { setMessages } from '@/lib/redux/slices/chat';
import { setErrors } from '@/lib/redux/slices/errors';
import { useAppDispatch, useAppSelector } from '@/lib/redux/store';
import { useEffect } from 'react';

export default async function Chat() {
    const { messages } = useAppSelector(state => state.chatReducer);

    const dispatch = useAppDispatch();

    console.log('CHAT');

    const getMessages = async () => {
        try {
            const query = `query {
  messageSents(orderBy:blockNumber) {
    id
    sender
    _theMessage
    blockNumber
  }
};

        const messageRes = await (
            await fetch('https://api.thegraph.com/subgraphs/name/moneydev1111/mychatapp', {
                method: 'POST',
                body: JSON.stringify({ query }),
            })
        ).json();

        dispatch(setMessages(messageRes.data.messageSents));
    } catch (error) {
        dispatch(setErrors([error]));
    }
};

useEffect(() => {
    getMessages();

    // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);


return (
    <div></div>
);

}

BTW if to comment out the const { messages } = useAppSelector(state => state.chatReducer); or dispatch(setMessages(messageRes.data.messageSents)); line problems isn't there, but it's natural and obvious I guess...

the slice code:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface MessageReq {
    id: string;
    sender: string;
    _theMessage: string;
    blockNumber: string;
}
interface InitialState {
    messages: MessageReq[];
}

const initialState: InitialState = {
    messages: [],
};

export const chat = createSlice({
    name: 'chat',
    initialState,
    reducers: {
        setMessages: (state, action: PayloadAction<MessageReq[]>) => {
            state.messages.push(...action.payload);
        },
    },
});

export const { setMessages } = chat.actions;

export default chat.reducer;

the store code:

import { configureStore } from '@reduxjs/toolkit';

import walletReducer from './slices/wallet';
import errorsReducer from './slices/errors';
import chatReducer from './slices/chat';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';

export const store = configureStore({
    reducer: {
        walletReducer,
        errorsReducer,
        chatReducer,
    },
    middleware: getDefaultMiddleware => getDefaultMiddleware({ serializableCheck: false }),
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

the provider code:

'use client';

import { store } from './store';
import { Provider } from 'react-redux';

export function ReduxProvider({ children }: { children: React.ReactNode }) {
    return <Provider store={store}>{children}</Provider>;
}

the layout code:

import './globals.css';
import './chat.css';
import { Inter } from 'next/font/google';
import Navbar from '@/components/Navbar';
import { ReduxProvider } from '@/lib/redux/provider';
import ChainList from '@/components/ChainList';
import Script from 'next/script';
import CustomScrollBar from '@/components/CustomScrollBar';

const inter = Inter({ subsets: ['latin'] });

export const metadata = {
    title: 'Create Next App',
    description: 'Generated by create next app',
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
        <html lang="en">
            <body className={inter.className}>
                <ReduxProvider>
                    <CustomScrollBar />
                    <Navbar />
                    {children}
                    {/* <ChainLogos /> */}
                    <ChainList />
                    {/* <Footer /> */}
                </ReduxProvider>
                <Script
                    src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
                    integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
                    crossOrigin="anonymous"
                    defer
                ></Script>
            </body>
        </html>
    );

}

I hope someone will see the issue right away..... because It seems like I tried everything.... Thanks a lot in advance!


Solution

  • OMG I had "async" word in the func component declaration......... like this export default async function Chat() {}