'useSelector doesn't update value in Next.js
I have a problem, createAsyncThunk
function makes request to server (axios) and then get data, after that extraReducers
handle builder.addCase
in it and makes state.value = action.payload
, then console.log(state.value)
writes value from server. Great! It works, but when I use useSelector
it sees existing value from initialState
but get value only when it was first time initialized (null
or just []
) not updated after dispatch in wrapper.getServerSIdeProps
. Same with just reducers and function in it. It works change state (console.log
write it) but useSelector
doesn't give me updated value.
Slice code
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import axios from 'axios';
import { HYDRATE } from 'next-redux-wrapper';
// types
import { IInitialStateV1 } from '../types/store';
import { ITrack } from '../types/tracks/track';
export const fetchData = createAsyncThunk('main/fetchData', async (): Promise<ITrack[]> => {
const { data } = await axios.get<ITrack[]>('http://localhost:5000/track');
return data;
})
const initialState: IInitialStateV1 = {
pause: true,
currentTime: 0,
volume: 0,
duration: 0,
active: null,
tracks: [],
}
export const mainSlice = createSlice({
name: 'main',
initialState,
reducers: {
setPause(state, action: PayloadAction<boolean>) {
state.pause = action.payload;
},
setTime(state, action: PayloadAction<number>) {
state.currentTime = action.payload;
},
setVolume(state, action: PayloadAction<number>) {
state.volume = action.payload;
},
setDuration(state, action: PayloadAction<number>) {
state.duration = action.payload;
},
setActive(state, action: PayloadAction<ITrack>) {
state.active = action.payload;
state.currentTime = 0;
state.duration = 0;
}
},
extraReducers: (builder) => {
// [HYDRATE]: (state, action) => {
// return {
// ...state,
// ...action.payload,
// }
// },
// [fetchData.fulfilled.toString()]: (state, action: PayloadAction<ITrack[]>) => {
// state.tracks = action.payload;
// }
builder.addCase(HYDRATE, (state, action: any) => {
return {
...state,
...action.payload,
}
}).addCase(fetchData.fulfilled, (state, action: PayloadAction<ITrack[]>) => {
// return {
// ...state,
// ...action.payload,
// }
state.tracks = action.payload;
});
}
})
export const { setPause, setTime, setVolume, setDuration, setActive } = mainSlice.actions;
export default mainSlice.reducer;
configurate store
import { AnyAction, configureStore, ThunkDispatch } from '@reduxjs/toolkit';
import { createWrapper, MakeStore, Context } from 'next-redux-wrapper';
import mainRed from './index';
const makeStore = () => configureStore({
reducer: {
main: mainRed
},
})
type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];
export type NextThunkDispatch = ThunkDispatch<RootState, void, AnyAction>;
export const wrapper = createWrapper<AppStore>(makeStore);
hooks for TypeScript
import { useDispatch, useSelector, TypedUseSelectorHook } from "react-redux";
import { RootState, AppDispatch } from "../store/reducer";
export const useTypeSelector: TypedUseSelectorHook<RootState> = useSelector;
export const useTypeDispath = ()=> useDispatch<AppDispatch>();
getServerSideProps
and useSelector
(in page)
import { Container, ListItem, Stack, Box, Button } from "@mui/material";
import TrackList from "../../components/TrackList";
// interfaces
import { ITrack } from "../../types/tracks/track";
// import hooks
import { useRouter } from "next/router";
import { useTypeSelector } from "../../hooks/useTypeSelector";
// wrapper
import { NextThunkDispatch, wrapper } from "../../store/reducer";
import { fetchData, setVolume } from "../../store";
export default function Index(): JSX.Element {
const router = useRouter();
const tracks: ITrack[] = useTypeSelector(state => state.main.tracks);
return (
<div className="main">
<Container >
<Stack marginTop={20} sx={{ backgroundColor: "#C4C4C4", fontSize: '24px', fontWeight: 'bold' }}>
<Box p={5} justifyContent="space-between">
<ListItem>List of Tracks</ListItem>
<Button variant="outlined" sx={{ backgroundColor: 'blue', color: 'white' }} onClick={() => router.push('/tracks/create')} >Upload</Button>
</Box>
<TrackList tracks={tracks} />
</Stack>
</Container>
</div>
)
}
export const getServerSideProps = wrapper.getServerSideProps((store) => async () => {
const dispatch = store.dispatch as NextThunkDispatch;
// dispatch(fetchData());
dispatch(setVolume(2));
return {
props: {}
}
})
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|