I have a problem on my project. I decide to migrate all the project to latest version. All is ok but, I have some problems with context and getServerSideProps.
I have some cards in my first page. There are from the api. When I click on it, the redirection to the right page is ok. But It didn’t take my GetServerSideProps and call the api to have all data.
My Dependencies :
- next : 14.1.4
- next-redux-wrapper : 8.1.0
- react : 18
- react-redux : 9.1.1
- redux : 5.0.1
- redux-saga : 1.3.0
- typescript: 5.3.3
I don’t have a lot of experience in React and Nextjs.
Thanks in advance and tell me if you need more code or explanation
pages/room/[id].tsx :
import React from 'react';
import { NextPage } from 'next';
import { withTranslation, I18n, TFunction } from 'next-i18next';
import { Room } from '@layouts/Room';
import RoomProvider from '@containers/Room';
import { LANGUAGE_OPTIONS } from '@constants';
import { wrapper } from '@store/rootStore';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { actionFetchRoom } from '@store/room';
import Router from 'next/router';
type RoomPageProps = {
readonly t: TFunction;
readonly i18n: I18n;
};
const RoomPage: NextPage<RoomPageProps> = ({ t, i18n }) => {
return (
<RoomProvider>
<Room t={t} lang={i18n.language as LANGUAGE_OPTIONS} />
</RoomProvider>
);
};
export const getServerSideProps = wrapper.getServerSideProps(
(store) => async (ctx) => {
const { res, query } = ctx;
console.log('test');
const redirect = (): void => {
if (res) {
res.writeHead(302, { Location: '/' });
res.end();
} else {
Router.push('/');
}
};
if (!query.id) {
redirect();
return { props: {} };
}
const locale = ctx.locale || ctx.defaultLocale || process.env.NEXT_DEFAULT_LANGUAGE;
try {
store.dispatch(actionFetchRoom({ id: query.id as string }));
return {
props: {
...(await serverSideTranslations(locale, ['translation'])),
lang: locale as LANGUAGE_OPTIONS,
},
};
} catch (error) {
console.error('Error during getServerSideProps:', error);
redirect();
return { props: {} };
}
}
);
export default withTranslation('translation')(RoomPage);
/roomCard.tsx :
// some code
const handleClick = () => {
Router.push(`/room/${url ? url : id}`);
};
// some code
<div className="room__content">
<h2 className="title is-2">{name}</h2>
<Button style={buttonStyles} onClick={handleClick}>{t('home.discover-room')}</Button>
</div>
// some code
store/room/action.ts :
import { UnknownAction } from 'redux';
import {
BookingDateI,
BOOKING,
ROOM,
ROOM_PREVIEW,
ROOM_FILTERS,
} from '@interfaces';
import { LANGUAGE_OPTIONS } from '@constants';
import { Router } from 'next/router';
export enum RoomAction {
FETCH_ROOM_LIST = 'FETCH_ROOM_LIST',
FETCH_ROOM_LIST_COMPLETE = 'FETCH_ROOM_LIST_COMPLETE',
FETCH_ROOM_LIST_ERROR = 'FETCH_ROOM_LIST_ERROR',
FETCH_ROOM = 'FETCH_ROOM',
FETCH_ROOM_COMPLETE = 'FETCH_ROOM_COMPLETE',
FETCH_ROOM_ERROR = 'FETCH_ROOM_ERROR',
FETCH_DATES = 'FETCH_DATES',
FETCH_DATES_COMPLETE = 'FETCH_DATES_COMPLETE',
FETCH_DATES_ERROR = 'FETCH_DATES_ERROR',
BOOKING_FIRST_STEP = 'BOOKING_FIRST_STEP',
BOOKING_FIRST_STEP_COMPLETE = 'BOOKING_FIRST_STEP_COMPLETE',
BOOKING_FIRST_STEP_ERROR = 'BOOKING_FIRST_STEP_ERROR',
BOOKING_SECOND_STEP = 'BOOKING_SECOND_STEP',
BOOKING_SECOND_STEP_COMPLETE = 'BOOKING_SECOND_STEP_COMPLETE',
BOOKING_SECOND_STEP_ERROR = 'BOOKING_SECOND_STEP_ERROR',
FETCH_BOOKING = 'FETCH_BOOKING',
FETCH_BOOKING_COMPLETE = 'FETCH_BOOKING_COMPLETE',
FETCH_BOOKING_ERROR = 'FETCH_BOOKING_ERROR',
}
export interface ActionFetchDates {
readonly RequestData: {
room_id: string;
start_at?: string;
end_at?: string;
};
readonly ResponseData: {
end_at: string;
dates: {
[date: string]: BookingDateI;
};
};
readonly ResponseError: ResponseError;
}
export function actionFetchDates(
payload: ActionFetchDates['RequestData'],
): UnknownAction {
return {
type: RoomAction.FETCH_DATES,
payload,
};
}
export function actionFetchDatesComplete(
payload: ActionFetchDates['ResponseData'],
): UnknownAction {
return {
type: RoomAction.FETCH_DATES_COMPLETE,
payload,
};
}
export function actionFetchDatesError(
payload: ActionFetchDates['ResponseError'],
): UnknownAction {
return {
type: RoomAction.FETCH_DATES_ERROR,
payload,
};
}
export interface ActionFetchRoom {
readonly RequestData: {
id: string;
};
readonly ResponseData: ROOM;
readonly ResponseError: ResponseError;
}
export function actionFetchRoom(
payload: ActionFetchRoom['RequestData'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM,
payload,
};
}
export function actionFetchRoomComplete(
payload: ActionFetchRoom['ResponseData'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM_COMPLETE,
payload,
};
}
export function actionFetchRoomError(
payload: ActionFetchRoom['ResponseError'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM_ERROR,
payload,
};
}
export interface ActionBookingFirstStep {
readonly RequestData: {
room_id: string;
date: string;
time_start: string;
};
readonly ResponseData: BOOKING;
readonly ResponseError: ResponseError;
}
export function actionBookingFirstStep(
payload: ActionBookingFirstStep['RequestData'],
): UnknownAction {
return {
type: RoomAction.BOOKING_FIRST_STEP,
payload,
};
}
export function actionBookingFirstStepComplete(
payload: ActionBookingFirstStep['ResponseData'],
): UnknownAction {
Router.push(`/booking/${payload.id}`);
scrollTo(0, 0);
return {
type: RoomAction.BOOKING_FIRST_STEP_COMPLETE,
payload,
};
}
export function actionBookingFirstStepError(
payload: ActionBookingFirstStep['ResponseError'],
): UnknownAction {
return {
type: RoomAction.BOOKING_FIRST_STEP_ERROR,
payload,
};
}
export interface ActionBookingSecondStep {
readonly RequestData: {
booking_id: string;
last_name: string;
first_name: string;
email: string;
phone_number: string;
number_players_adults: number;
number_players_kids: number;
language: LANGUAGE_OPTIONS;
has_extra_service: boolean;
price: number;
discount: number;
total: number;
promo_code?: string;
};
readonly ResponseData: {
booking: BOOKING;
};
readonly ResponseError: ResponseError;
}
export function actionBookingSecondStep(
payload: ActionBookingSecondStep['RequestData'],
): UnknownAction {
return {
type: RoomAction.BOOKING_SECOND_STEP,
payload,
};
}
export function actionBookingSecondStepComplete(
payload: ActionBookingSecondStep['ResponseData'],
): UnknownAction {
return {
type: RoomAction.BOOKING_SECOND_STEP_COMPLETE,
payload,
};
}
export function actionBookingSecondStepError(
payload: ActionBookingSecondStep['ResponseError'],
): UnknownAction {
return {
type: RoomAction.BOOKING_SECOND_STEP_ERROR,
payload,
};
}
export interface ActionFetchBooking {
readonly RequestData: {
id: string;
};
readonly ResponseData: {
booking: BOOKING;
};
readonly ResponseError: ResponseError;
}
export function actionFetchBooking(
payload: ActionFetchBooking['RequestData'],
): UnknownAction {
return {
type: RoomAction.FETCH_BOOKING,
payload,
};
}
export function actionFetchBookingComplete(
payload: ActionFetchBooking['ResponseData'],
): UnknownAction {
return {
type: RoomAction.FETCH_BOOKING_COMPLETE,
payload,
};
}
export function actionFetchBookingError(
payload: ActionFetchBooking['ResponseError'],
): UnknownAction {
return {
type: RoomAction.FETCH_BOOKING_ERROR,
payload,
};
}
export interface ActionFetchRoomList {
readonly RequestData: {
filters: ROOM_FILTERS;
};
readonly ResponseData: Array<ROOM_PREVIEW>;
readonly ResponseError: ResponseError;
}
export function actionFetchRoomList(
payload: ActionFetchRoomList['RequestData'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM_LIST,
payload,
};
}
export function actionFetchRoomListComplete(
payload: ActionFetchRoomList['ResponseData'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM_LIST_COMPLETE,
payload,
};
}
export function actionFetchRoomListError(
payload: ActionFetchRoomList['ResponseError'],
): UnknownAction {
return {
type: RoomAction.FETCH_ROOM_LIST_ERROR,
payload,
};
}
store/room/reducer.ts
import {ActionFetchDates, RoomAction} from './actions';
import {BOOKING, ROOM, ROOM_PREVIEW} from '@interfaces';
import {AnyAction} from "redux";
export interface RoomReducerState {
room?: ROOM;
roomList?: Array<ROOM_PREVIEW>;
currentRoomSchedule?: ActionFetchDates['ResponseData']['dates'];
scheduleEndAt?: string;
bookingInProcess?: BOOKING;
loading: boolean;
errors: string | ResponseError | null;
}
const initialState: RoomReducerState = {
loading: false,
errors: null,
};
export const roomReducer = (
state = initialState,
action: AnyAction,
): RoomReducerState => {
switch (action.type) {
case RoomAction.FETCH_ROOM:
case RoomAction.FETCH_ROOM_LIST:
case RoomAction.FETCH_DATES:
case RoomAction.BOOKING_FIRST_STEP:
case RoomAction.BOOKING_SECOND_STEP:
case RoomAction.FETCH_BOOKING:
return {
...state,
errors: null,
loading: true,
};
case RoomAction.FETCH_DATES_COMPLETE:
return {
...state,
currentRoomSchedule: {
...state.currentRoomSchedule,
...action.payload.dates,
},
scheduleEndAt: action.payload.end_at,
loading: false,
errors: null,
};
case RoomAction.FETCH_DATES_ERROR:
return {
...state,
currentRoomSchedule: undefined,
scheduleEndAt: undefined,
errors: action.payload,
loading: false,
};
case RoomAction.FETCH_ROOM_LIST_COMPLETE:
return {
...state,
roomList: action.payload,
currentRoomSchedule: undefined,
scheduleEndAt: undefined,
loading: false,
errors: null,
};
case RoomAction.FETCH_ROOM_COMPLETE:
return {
...state,
room: action.payload,
currentRoomSchedule: undefined,
scheduleEndAt: undefined,
loading: false,
errors: null,
};
case RoomAction.BOOKING_FIRST_STEP_COMPLETE:
return {
...state,
bookingInProcess: action.payload,
loading: false,
errors: null,
};
case RoomAction.BOOKING_SECOND_STEP_COMPLETE:
return {
...state,
loading: false,
errors: null,
};
case RoomAction.FETCH_BOOKING_COMPLETE:
return {
...state,
bookingInProcess: action.payload,
loading: false,
errors: null,
};
case RoomAction.FETCH_ROOM_ERROR:
return {
...state,
room: undefined,
errors: action.payload,
loading: false,
};
case RoomAction.FETCH_ROOM_LIST_ERROR:
return {
...state,
roomList: undefined,
errors: action.payload,
loading: false,
};
case RoomAction.FETCH_BOOKING_ERROR:
return {
...state,
errors: action.payload,
loading: false,
};
case RoomAction.BOOKING_FIRST_STEP_ERROR:
case RoomAction.BOOKING_SECOND_STEP_ERROR:
return {
...state,
errors: action.payload,
loading: false,
};
default:
return state;
}
};
store/room/saga.ts
import { call, put, Effect } from 'redux-saga/effects';
import { AxiosResponse } from 'axios';
import client, { API_ROUTES } from '@http-client';
import * as RoomActions from './actions';
import {AnyAction, UnknownAction} from "redux";
export function* fetchRoomWorker(action: UnknownAction): IterableIterator<Effect> {
let response: AxiosResponse<RoomActions.ActionFetchRoom['ResponseData']> | undefined;
console.log('fetch room');
try {
response = yield call(() =>
client.get(`${API_ROUTES.room}/${action.payload.id}`),
);
yield put(RoomActions.actionFetchRoomComplete(response?.data?.room));
} catch (error) {
yield put(RoomActions.actionFetchRoomError(error.response));
}
}
export function* fetchDatesWorker(action: UnknownAction): IterableIterator<Effect> {
console.log('fetchDatesWorkers');
let response: AxiosResponse<RoomActions.ActionFetchDates['ResponseData']> | undefined;
try {
response = yield call(() =>
client.get(
`${API_ROUTES.roomBookingDates}/${action.payload.room_id}?start_at=${action.payload.start_at}&end_at=${action.payload.end_at}`,
),
);
yield put(
RoomActions.actionFetchDatesComplete({
end_at: action.payload.end_at || '',
dates: response?.data?.data,
}),
);
} catch (error) {
yield put(RoomActions.actionFetchDatesError(error.response));
}
}
export function* fetchBookingWorker(action: AnyAction): IterableIterator<Effect> {
let response: AxiosResponse<RoomActions.ActionFetchBooking['ResponseData']> | undefined;
try {
response = yield call(() =>
client.get(`${API_ROUTES.fetchBooking}/${action.payload.id}`),
);
yield put(RoomActions.actionFetchBookingComplete(response?.data?.booking));
} catch (error) {
yield put(RoomActions.actionFetchBookingError(error.response));
}
}
export function* bookingFirstStepWorker(action: AnyAction): IterableIterator<Effect> {
let response: AxiosResponse<RoomActions.ActionBookingFirstStep['ResponseData']> | undefined;
const { room_id, ...data } = action.payload;
try {
response = yield call(() =>
client.post(`${API_ROUTES.bookingFirstStep}/${room_id}`, data),
);
yield put(RoomActions.actionBookingFirstStepComplete(response?.data?.booking));
} catch (error) {
yield put(RoomActions.actionBookingFirstStepError(error.response));
}
}
export function* bookingSecondStepWorker(action: AnyAction): IterableIterator<Effect> {
let response: AxiosResponse<RoomActions.ActionBookingSecondStep['ResponseData']> | undefined;
const { booking_id, ...data } = action.payload;
try {
response = yield call(() =>
client.post(`${API_ROUTES.bookingSecondStep}/${booking_id}`, data),
);
yield put(RoomActions.actionBookingSecondStepComplete(response?.data?.booking));
} catch (error) {
yield put(RoomActions.actionBookingSecondStepError(error.response));
}
}
export function* fetchRoomListWorker(action: AnyAction): IterableIterator<Effect> {
let response: AxiosResponse<RoomActions.ActionFetchRoomList['ResponseData']> | undefined;
try {
response = yield call(() =>
client.post(`${API_ROUTES.rooms}`, { filters: action.payload.filters }),
);
yield put(RoomActions.actionFetchRoomListComplete(response?.data?.data));
} catch (error) {
yield put(RoomActions.actionFetchRoomListError(error.response));
}
}
Staldu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.