1

Problem: My next.js app crash on client side because of empty store object, but if I try to read this object in getServerSideProps it`s ok.

I have 2 pages in my app, profile/[id] and post/[id], all of them have getServerSideProps

User flow:

  1. User coming on profile/[id] by friend`s link
  2. On profile/[id] page he has profile data and 3x3 posts grid, every post is a link to post/[id]
  3. Click on post
  4. Navigate to post/[id] - here he has some post data: username, image, createdAt etc...

Expected: Server render html for post page after successful request

Received: Client crash after trying to read field of empty object

Question: Can you tell my what's wrong with my code? I have HYDRATE for postSlice and default next-redux-wrapper code so I'm confused.

Code:

  1. store.ts
import {configureStore} from "@reduxjs/toolkit";
import {createWrapper} from "next-redux-wrapper";
import profileSlice from './reducers/profileSlice';
import postsSlice from './reducers/postsSlice';
import postSlice from './reducers/postSlice';

export const makeStore = () =>
    configureStore({
        reducer: {
            profile: profileSlice,
            posts: postsSlice,
            post: postSlice
        },
        devTools: true
    });

export type Store = ReturnType<typeof makeStore>;
export type RootState = ReturnType<Store['getState']>;

export const wrapper = createWrapper<Store>(makeStore);
  1. _app.tsx
//
...imports
//

function App({Component, ...rest}: AppProps) {
    const {store, props} = wrapper.useWrappedStore(rest);
    const {pageProps} = props;
    return (
        <Provider store={store}>
            <ApolloProvider client={client}>
                <GlobalStyle/>
                <ThemeProvider theme={theme}>
                    <LookyHead />
                    <Component {...pageProps} />
                </ThemeProvider>
            </ApolloProvider>
        </Provider>
    );
}

export default App;
  1. postSlice.ts
//
some imports and interfaces...
//

export const postSlice = createSlice({
    name: 'post',
    initialState,
    reducers: {
        setPost: (state, action) => {
            state.post = action.payload
        }
    },
    extraReducers: {
        [HYDRATE]: (state, action) => {
            return {
                ...state,
                ...action.payload.post,
            };
        },
    },
});

export const { setPost } = postSlice.actions;

export default postSlice.reducer;
  1. Post component of posts grid on profile, here i have link to post/[id]
function Post({previewUrl, likesCount, commentsCount, duration, id}: Props) {

    some code...
    
    return (
        <Link href={`/post/${id}`}>
            <Container
                onMouseEnter={() => setIsHover(true)}
                onMouseLeave={() => setIsHover(false)}
            >
                <img src={previewUrl} alt="image"/>
                <PostFooter
                    isHover={isHover}
                    likesCount={likesCount}
                    commentsCount={commentsCount}
                    time={time}
                />
            </Container>
        </Link>
    );
}

export default memo(Post);
  1. getServerSideProps in post/[id]
export const getServerSideProps =
    wrapper.getServerSideProps(
        (store) =>
            async ({query}) => {
                const id = query!.id as string
                try {
                    const {data} = await client.query<Res, Vars>({
                        query: GET_POST,
                        variables: {
                            postId: id
                        }
                    });
                    console.log(data.publicPost) // Here I have data!
                    store.dispatch(setPost(data.publicPost))
                } catch (e) {
                    console.log(e)
                }
                return {
                    props: {}
                }
            })

export default Post;
  1. Data component inside post/[id], where client crash
//
 imports...
//

function Data() {
    const {post} = useAppSelector(({post}) => post) // looks weird but its ok

    const parsed = parseISO(post?.createdAt) // Here my client fall
    const date = format(parsed, 'dd MMMM yyyy, HH:MM', {locale: enGB})

    return (
        ...
    );
}

export default Data;

0 Answers0