해결된 질문
작성
·
1K
0
안녕하세요! 강의 잘 듣고 있습니다.
다름이 아니라, 유사 에러 겪은 다른 학생들 질문 찾아봤는데도 해결이 안되서 질문드립니다.
다른 페이지에서는 저 에러가 안 뜨는데 index 페이지에만 가면 state가 전부 초기화가 되네요. 그리고 해당 문구가 계속 무한루프 돌듯이 반복되구요. 또 실행 잘 되다가 갑자기 저럴 때가 생깁니다.
// reducers 내부 index.js
import { HYDRATE } from "next-redux-wrapper";
import { combineReducers } from "@reduxjs/toolkit";
import userSlice from "./user";
import alertSlice from "./alert";
const rootReducer = (state, action) => {
switch (action.type) {
case HYDRATE:
console.log("root reducer", state, action);
return { ...state, ...action.payload };
default: {
const combinedReducer = combineReducers({
user: userSlice.reducer,
alert: alertSlice.reducer,
});
return combinedReducer(state, action);
}
}
};
export default rootReducer;
// actions user.js
export const fetchUser = async () => {
const response = await api.get(`/users/load`);
console.log(response.data);
return response.data;
};
export const loadUser = createAsyncThunk("user/loadUser", fetchUser);
// reducers user.js
import { createSlice } from "@reduxjs/toolkit";
import { loadUser } from "../action/user";
const initialState = {
userData: null,
requestId: null,
auth: false,
};
const userSlice = createSlice({
name: "user",
initialState,
extraReducers: (builder) =>
builder
.addCase(loadUser.pending, (state, action) => {
const { meta } = action;
state.requestId = meta.requestId;
return {
...state,
};
})
.addCase(loadUser.fulfilled, (state, action) => {
state.requestId = null;
state.auth = true;
state.userData = action.payload;
return {
...state,
};
})
.addCase(loadUser.rejected, (state) => {
state.requestId = null;
state.auth = false;
return {
...state,
};
})
.addDefaultCase((state) => {
return { ...state };
}),
});
export default userSlice;
// store/index.js
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import { createWrapper } from "next-redux-wrapper";
import rootReducer from "../reducer";
const store = configureStore({
middleware: [...getDefaultMiddleware()],
reducer: rootReducer,
devTools: process.env.NODE_ENV !== "production",
});
export const makeStore = (context) => store;
const wrapper = createWrapper(makeStore, {
debug: process.env.NODE_ENV !== "production",
});
export default wrapper;
// pages/index.js
// 컴포넌트 코드 생략
export const getServerSideProps = wrapper.getServerSideProps(
async (context) => {
console.log("getServerSideProps start");
console.log(context.req.headers);
const cookie = context.req ? context.req.headers.cookie : "";
axios.defaults.headers.Cookie = "";
if (context.req && cookie) {
axios.defaults.headers.Cookie = cookie;
}
context.store.dispatch(loadUser());
console.log("getServerSideProps end");
},
);
답변 16
1
0
일단 get요청은 전부 swr로 대체하고 확인해보니 개발모드 서버 가동한 상태에서 수정 후 자동으로 업데이트되면서 생기더군요ㅠㅠ 클라이언트 사이드로 할 땐 해당 에러가 발생하지 않았습니다.
0
0
오 감사합니다! 이제 구동은 됐는데, 처음 렌더링 시 상태가 페이지를 넘어갈 때 발생하는 엑션들이 리듀서에 적용이 안 된채로 진행 되는 에러가 있긴 하네요ㅠㅠ get serverside props 함수 내부에 dispatch promise 결과까지 찍어보았어요.
context.store
.dispatch(loadChannelProfile(channelid))
.then((res) => console.log(res))
.catch((err) => console.error(err));
요청은 잘 들어왔는데, 상태 업데이트가 계속 안되다가 다시 hydrate 적용할 당시랑 똑같은 문제가 뜨네요... 처음 돌려보았을 때 메인페이지는 잘 나왔었는데ㅠㅠ 그래서 서버 껐다 다시 켜면 메인만 또 제대로 나오고 라우터 넘어갈 시 바뀐 상태가 적용이 안되요.. 그 saga에서 하는것처럼 toPromise랑 end 처리를 해줘야 하나요? 아래 코드는 컴포넌트 아래 serverside props 입니다.
export const getServerSideProps = wrapper.getServerSideProps(
async (context) => {
const cookie = context.req ? context.req.headers.cookie : "";
axios.defaults.headers.Cookie = "";
if (context.req && cookie) {
axios.defaults.headers.Cookie = cookie;
}
const { channelid } = context.params;
console.log(channelid);
context.store.dispatch(loadUser());
context.store
.dispatch(loadChannelProfile(channelid))
.then((res) => console.log(res))
.catch((err) => console.error(err));
await context.store.dispatch(
channelSlice.actions.loadChannelProfileFinished(),
);
return { props: {} };
},
);
0
0
바꿔도 똑같은 에러가 반복되서 브라우저 콘솔창에서 확인해봤는데 빈 state로 들어왔네요ㅠ 일단 __NEXT_DATA__는 브라우저에서 렌더링이 되었고, makestore에서 context도 콘솔에 req, res 모두 찍혔습니다. 비동기 처리를 한번 더 해야할까요..
[코드]
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import { createWrapper } from "next-redux-wrapper";
import rootReducer from "../reducer";
function getServerState() {
return typeof window !== undefined && typeof document !== undefined
? JSON.parse(document.getElementById("__NEXT_DATA__").textContent).props
.pageProps.initialState
: undefined;
}
const makeStore = (context) => {
console.log(context);
return configureStore({
middleware: [...getDefaultMiddleware()],
reducer: rootReducer,
devTools: process.env.NODE_ENV !== "production",
preloadedState: getServerState(),
});
};
const wrapper = createWrapper(makeStore, {
debug: process.env.NODE_ENV !== "production",
});
export default wrapper;
0
preloadedState: document ? getServerState() : undefined,
이것 때문에 에러나는 겁니다. 그냥 getServerState()만 쓰세요
0
동일한 오류가 계속 뜨네요ㅠㅠ 일단 GET요청 일부는 급하니까 swr로 빼고, 이부분 완전 수정해서 적용해야 할 것 같네요ㅠ 혹시 store/index.js가 브라우저가 아니라 node에서 돌아가서 document를 못 읽어서 생기는 오류는 아니죠?
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import { createWrapper } from "next-redux-wrapper";
import rootReducer from "../reducer";
function getServerState() {
return typeof typeof window !== undefined && document !== undefined
? JSON.parse(document.getElementById("__NEXT_DATA__").textContent).props
.pageProps.initialState
: undefined;
}
const makeStore = (context) => {
console.log(context);
return configureStore({
middleware: [...getDefaultMiddleware()],
reducer: rootReducer,
devTools: process.env.NODE_ENV !== "production",
preloadedState: document ? getServerState() : undefined,
});
};
const wrapper = createWrapper(makeStore, {
debug: process.env.NODE_ENV !== "production",
});
export default wrapper;
0
preloadedState: getServerState()로 두고
function getServerState() {
return typeof document !== undefined? JSON.parse(...) : undefined
}
안쪽으로 넣어보세요.
0
똑같은 에러가 뜨는데, 혹시 _app.js나 _document.js 파일을 손봐야할까요?ㅠㅠ
// _app.js
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import Head from "next/head";
import wrapper from "../app/store";
import { appShortTitle, appDescription } from "../app/helper/appTitle";
function App({ Component, pageProps }) {
useEffect(() => {
if ("serviceWorker" in navigator) {
window.addEventListener("load", function () {
navigator.serviceWorker.register("/sw.js").then(
function (registration) {
console.log(
"Service Worker registration successful with scope: ",
registration.scope,
);
},
function (err) {
console.log("Service Worker registration failed: ", err);
},
);
});
}
}, []);
return (
<>
<Head>
<meta charSet="utf-8" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<meta property="og:image" content="/thumbnail.jpg" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
<meta name={appShortTitle} content={appDescription} />
<meta property={"og:title"} name={appShortTitle} />
<meta property={"og:description"} content={appDescription} />
</Head>
<Component {...pageProps} />
</>
);
}
App.propTypes = {
Component: PropTypes.elementType.isRequired,
};
export default wrapper.withRedux(App);
0
typeof window !== undefined && typeof document !== undefined ? getServerState() : undefined
이렇게 하면요?
0
0
https://forum.playcanvas.com/t/uncaught-referenceerror-document-is-not-defined/13073/8 여기서 시키는 대로 하니 이런 에러가 뜨네요ㅠ
0
_error.js를 다음과 같이 바꿔도 똑같은 결과가 나옵니다ㅠ
export const getServerSideProps = wrapper.getServerSideProps(
async (context) => {
const { res, error } = context;
const statusCode = res ? res.statusCode : error ? error.statusCode : null;
const cookie = context.req ? context.req.headers.cookie : "";
axios.defaults.headers.Cookie = "";
if (context.req && cookie) {
axios.defaults.headers.Cookie = cookie;
}
context.store.dispatch(loadUser());
const { tagname } = context.params;
console.log(tagname);
return { props: { statusCode } };
},
);
0
다른 페이지는 _error.js 를 제외하고 전부 다 똑같이 적용 되었습니다! error.js는 커스텀 페이지라 이렇게 적었어요ㅠㅠ
ErrorPage.getInitialProps = ({ res, error }) => {
const statusCode = res ? res.statusCode : error ? error.statusCode : null;
return { statusCode };
};
말씀하신대로 적용해봤는데 store/index.js에서 미리 읽고 해서 그런가 not defined 에러가 뜨네요ㅠㅠ
0
다른 페이지에는 getServerSideProps가 있나요? 다른 페이지에서 새로고침하면 어떻게 되나요?
저는 툴킷 쓰실 때는 hydrate 액션 지우시고 다음과 같이 쓰시는 걸 추천드립니다.
function getServerState() {
return JSON.parse(document.getElementById('__NEXT_DATA__').textContent).props.pageProps.initialState;
}
const store = configureStore({
reducer,
middleware: [...getDefaultMiddleware()],
preloadedState: typeof window !== undefined ? getServerState() : undefined
});