seminar-2022 icon indicating copy to clipboard operation
seminar-2022 copied to clipboard

React 세미나2 url 변경 시 context 값이 초기화되는 현상에 관한 질문

Open fluentmin opened this issue 2 years ago • 2 comments

안녕하세요. 세미나2 과제 관련해서 구글 검색을 해도 방법을 찾지 못해 질문드립니다.

URL을 변경하면, 기존의 메뉴와 로그인 context가 초기화되는 문제입니다. 예를 들면 아래와 같습니다.

  • 로그인한 상태에서 URL을 통해 이동하고자 menus/4를 입력하면 로그인 상태가 해제됩니다.
  • 메뉴를 추가한 뒤, 추가된 메뉴를 보고자 URL에 stores/1를 입력하면 기본 메뉴만 남아있습니다.

헤더를 비롯한 각 컴포넌트 내의 Link 를 이용하여 이동할 때는 이러한 문제가 발생하지 않습니다.

현재 제 App 컴포넌트는 대략 아래와 같습니다. (과제 수행과 관련하여 문제되는 부분이 있다면 수정하겠습니다)

... // data.json을 data로 import한 상태
function App() {
  const [menuItems, setMenuItems] = useState(data);
  const [loginObj, setLoginObj] = useState({
    isLogin: false,
    id: "",
    password: "",
    });
  return (
      <div>
        <SessionContext.Provider value={{ loginObj, setLoginObj }}> // SessionContext.js 파일을 import한 상태
          <MenuDataContext.Provider value={{ menuItems, setMenuItems }}> // MenuDataContext.js 파일을 import한 상태
            <BrowserRouter>
              <Routes> 
                  ... // Route 들
              </Routes>
            </BrowserRouter>
          </MenuDataContext.Provider>
        </SessionContext.Provider>
      </div>
  });

문제가 발생한 이유를 파악하기 위해 이 App 컴포넌트의 return 문 위에 console.log를 입력해보았는데, URL을 바꿔 입력할 때마다 콘솔에 찍혔습니다. 이를 통해 App의 useState를 이용한 부분 역시 URL이 바뀌어 입력될 때마다 새로 실행되고, 이 때문에 menuItemsloginObj역시 초기화되는 것이라고 생각하였습니다. 그러나 이후에 어떻게 이 문제를 해결해야할지에 대한 방법을 찾지 못하고 있습니다. 혹시 이와 관련하여 도움 주신다면 정말 감사하겠습니다!

fluentmin avatar Oct 11 '22 13:10 fluentmin

react-router가 제공하는 Link와 navigate 등을 통해 링크를 바꾸는 경우, 일반적인 a 태그처럼 새로 페이지를 불러오는 것이 아니라 주소값만 바꾸어 새로 렌더링하게 됩니다. 하지만 주소창을 직접 수정하여 이동하는 경우 기본적으로 모든 HTML+CSS+JS를 서버에서 새로 불러오게 됩니다. 새로고침할 때처럼 내부적으로 저장되어있던 useState나 context의 모든 상태들도 초기화되는 것이 당연합니다. 이를 막으려면 로컬스토리지나 쿠키에 필요한 값을 저장하여 페이지 전환 간에도 상태를 유지할 수 있습니다. 이번 과제에서 해당 부분은 채점하지 않겠지만 연습 삼아 해보시는 것도 괜찮을 것 같습니다. setLoginObj를 그대로 넘기 않고 스토리지에 저장하도록 persistLoginObj로 한번 감싸서 provider의 value로 넣어줄 수 있겠습니다.

useEffect(() => {
    const storedLoginObj = localStorage.getItem("loginObj"));
    setLoginObj(JSON.parse(storedLoginObj));
}, []); // 빈 dependency array를 설정하면 마운트될 때 한번만 실행됩니다.
function persistLoginObj(newLoginObj) {
    setLoginObj(newLoginObj);
    localStorage.setItem("loginObj", JSON.stringify(newLoginObj));
}

joongwon avatar Oct 12 '22 00:10 joongwon

답변 감사합니다! context를 사용하는 게 처음이다보니 서툴러서 발생한 문제인 줄 알았는데, 당연한 것이었군요. 로컬 스토리지를 이용하는 코드도 첨부해주셔서 감사합니다. 참고하여 관련된 부분 찾아보고, 코드에도 반영해보겠습니다!(아마 다음 과제에..)

fluentmin avatar Oct 12 '22 10:10 fluentmin