I have a react app that was working until I converted over to a nextjs app. The axios call is being made, the data is being returned but not being stored(the selectors are showing undefined). I suspect it is a setup issue in the conversion.
The call which works:
React.useEffect(() => {
dispatch(fetchCoinsByMarketCap()); // coin gecko
}, [dispatch]);
The slice. I am logging correct data and status in my fetchCoinsByMarketCap.fulfilled
case:
import axios from "axios";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { coinGecko } from "../../url/urlList";
const initialState = {
coinsMCap: [],
status: "idle",
error: null,
};
export const fetchCoinsByMarketCap = createAsyncThunk(
"coinsByMarketCap/fetchCoinsByMarketCap",
async () => {
const res = await coinGecko.get(
`/coins/markets/?
vs_currency=usd&order=market_cap_desc&per_page=50&page=1&sparkline=false`
);
return res.data;
}
);
export const marketCapSlice = createSlice({
name: "coinsByMarketCap",
initialState,
reducers: {
updateCoinsMcapState: (state, action) => {
Object.assign(state, action.payload);
},
},
extraReducers(builder) {
builder
.addCase(fetchCoinsByMarketCap.pending, (state) => {
state.status = "loading";
})
.addCase(fetchCoinsByMarketCap.fulfilled, (state, action) => {
state.coinsMCap = action.payload;
state.status = "succeeded";
console.log("sc: ", state.coinsMCap);
console.log("ss: ", state.status);
})
.addCase(fetchCoinsByMarketCap.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export const { updateCoinsMcapState } = marketCapSlice.actions;
export default marketCapSlice.reducer;
My store:
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { createWrapper } from "next-redux-wrapper";
import reducer from "./rootReducer";
const middleware = [thunk];
const makeStore = () =>
createStore(reducer, compose(applyMiddleware(...middleware)));
export const wrapper = createWrapper(makeStore);
The next _app file which has the wrapper.withRedux export:
import React from "react";
import { wrapper } from "../redux/store";
const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
export default wrapper.withRedux(MyApp);
The root reducer:
import { combineReducers } from "redux";
import marketCapReducer from "./slices/marketCapSlice";
const reducer = combineReducers({
coinsByMarketCap: marketCapReducer,
});
export default reducer;
The selector file:
// marketCapSlice selectors
export const selectCoinsMCap = (state) => state.coinsByMarketCap.coinsMCap;
export const selectCoinsMCapStatus = (state) => state.coinsByMarketCap.status;
export const selectCoinsMCapError = (state) => state.coinsByMarketCap.error;
These selectors should have data after the axios call, but they don't. Again bear in mind that this used to work before I tried to convert it to next and the only thing I changed was the store and the _app.js files. The old store without next was very simple:
import { configureStore } from "@reduxjs/toolkit";
import reducer from "./rootReducer";
const store = configureStore({ reducer });
export default store;
And the standard provider setup in the old index:
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
Maybe one of you nextjs experts can help me.
CodePudding user response:
A reducer is supposed to return the updated state, as far as I know. It seems to me like you may have forgotten to return a value here:
reducers: {
updateCoinsMcapState: (state, action) => {
Object.assign(state, action.payload);
},
},
Should it be something like this?
reducers: {
updateCoinsMcapState: (state, action) => {
return Object.assign(state, action.payload);
},
},
CodePudding user response:
Here is the store setup that fixed it:
import { configureStore } from "@reduxjs/toolkit";
import { applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { createWrapper } from "next-redux-wrapper";
import reducer from "./rootReducer";
const middleware = [thunk];
const makeStore = () =>
configureStore({ reducer }, compose(applyMiddleware(...middleware)));
export const wrapper = createWrapper(makeStore);
I used configureStore instead of createStore and enclosed reducer in curly braces.