본문 바로가기
항해99/실전 WIL | TIL

[TIL-020] Redux를 사용하여 상태 관리를 해야 하는 이유

by junvely 2023. 5. 2.

Today목표 : 05/01일 React Lv4 과제(2)-Redux를 사용하여 상태관리를 해야 하는 이유


Redux를 사용하여 상태관리를 해야 하는 이유 

오늘 튜터님과의 면담이 있었다. Lv4 과제를 진행하기 위해 현재 컴포넌트 구조와 디자인은 다 마쳐 놓았지만, 아직 기능 구현은 못하고 있었다. 그 이유는

1. JSON서버와 리덕스를 사용하면서 어디까지 상태를 Redux에서 관리해 주어야 하는지,

2. JSON서버와 리덕스 상태를 동시에 계속해서 변경해 주어야 하는 번거로움을 해결할 수 있는 방법이 없는지에 대해 감이 안잡히고 있었기 때문이었다.

일단 JSON서버, Redux-toolkit, React-query를 사용하겠다는 것이 분명해졌으니 먼저 기능 구현을 위해 내가 모르고 있는 점들을 정리해 보아야 겠다는 필요성이 들었다.

 

내가 고민하는 부분, 모르는 부분들은 다음과 같았다.

1. Redux에서 관리해야 할 상태의 범위 

- 컴포넌트 내의 작은 상태값도 관리해야 하는가? (확장성, 재사용성 고려) ✅

- 컴포넌트 내의 작은 상태값일 지라도 1depth 이상 props으로 전달될 경우 Redux에서 관리해 주어야 하는가? ✅

- Redux에서 관리해야 하는 Reducer 상태 구성의 기준은 무엇인가? (todos에서 todos와 todo를 관리, 또는 따로 reducer생성? modal 등은?)

 

 

=> ❗이에 대한 고민을 해결하기 위해서는 Redux에 대한 장점을 고려해 보아야 했다. 장점은 다음과 같은 것 같다.

1. Redux를 사용하면 상태의 중앙 집중화가 되기 때문에 프로젝트의 확장성, 상태값 재사용성, props드릴링 방지할 수 있다. 한 곳에서 관리하여 유지보수가 용이하다. 알아서 불변성을 유지시켜 준다. 상태값을 추적하기 쉬워 디버깅이 용이하다(devtools). 작은 상태값이더라도 확장성을 고려하고, 이와같은 Redux의 기능들을 이용하고자 한다면 Redux를 사용하는게 익숙해지기만 한다면 나쁠 것은 없을 것 같다. 내가 생각하는 가장 장점은 상태값을 추적가능하다는 것과, props드릴링을 방지하여 의존도를 낮출 수 있다는 것이었다. 따라서 지금은 어떤 방법이 더 좋을지는 모르겠지만 나중에는 사용하다보면 기준이 생기리라 생각하고 Redux 사용에 익숙해지기 위해 웬만하면 모두 Redux에서 상태를 관리해보려고 한다. 추가로 Recoil도 많이 사용한다고 하니 나중에 참고하여 배워보도록 하자.

2. 이제 모달과 작은 상태값들은 어떤 Reducer에서 어떻게 관리해야 할지가 고민이다.

=> 전역적으로 사용해야 하는 todos, todo, modal 등으로 정했다. input값을 전달한다거나 컴포넌트 내에서 해결 가능한 state는 굳이 전역으로 두지 않았다.

 

2. JSON서버와 Redux상태 관리 같이 사용하기

- 서버에 데이터를 요청 및 CRUD하는 로직들은 따로 두어야 하는가? ✅

- 데이터 변경 요청과 동시에 매번 Redux상태도 같이 변경해야 하는가? ✅

=> 1. 서버의 데이터 통신을 하는 로직은 비즈니스 로직과 따로 두는게 좋으므로 따로 함수로 관리 해야겠다.

2. 첫 마운트 시 데이터를 가져와서 전역으로 사용하고, 데이터를 가져올 때는 매번 서버에 요청하지 않고 전역 상태값을 사용해야 겠다. 추가, 수정, 삭제 시에는 무조건 서버의 데이터도 변경되야 하는 것은 같기 때문에 서버 데이터 변경 시 마다 다시 전역 상태를 업데이트 하기 => 이 때 마다 서버에 데이터를 요청하여 가져오는 함수 실행해야 겠다.

더 나은 방법이 있는지는 Reat qeury를 공부해 봐야 겠지만, 일단 여기까지 진행 후, 다시 React query를 공부하여 리팩토링하는 방식으로 진행해 봐야 겠다.

 


axios는 프로미스를 반환한다

1. 따라서 .then(), .catch() 또는 try, catch문으로 프로미스의 결과값 처리를 해주고,

객체 안의 data결과값을 추출해 변수에 담아 return 한다.

//axios.js
export const getPosts = async () => {
  try {
    const { data } = await Axios.get("/posts");
    return data;
  } catch (error) {
    console.log("axios getPosts Error :", error);
  }
};

2. ❗매우중요❗데이터를 사용하는 함수에서 비동기 처리를 해주지 않으면 이 Promise 객체는 데이터를 비동기적으로 가져오는 중이므로 Promise pending 객체 상태를 반환한다.... 따라서 꼭 async-await 등의 처리를 해줘야 한다. 

  const getPostsData = async () => {
    const data = await getPosts();
    setPosts(data);
  };

 


새로고침이 되면 전역 상태값이 초기화 된다

❗상세 페이지 url에서 id경로 변경시 데이터를 가져오지 못하는 문제 발생

=> 새로고침이 되면 전역 상태값이 초기화 되는 문제 

문제 코드

function PostPage() {
  const [modalToggle, setModalToggle] = useState(false);

  // param.id로 post가져오기
  const { id } = useParams();
  const post = useSelector((state) =>
    state.postsSlice.posts.find((post) => post.id == id)
  );

postPage 상세페이지의 params의 id에 따라 전역 상태 posts에서 post정보를 가져오도록 하였다.

이때, url경로를 변경하면 post정보를 가져오지 못했다.

문제는, postsPage에서 posts에 대한 데이터를 서버에서 가져와 전역 상태값을 저장하도록 하였는데, Redux도 전역 상태이기 때문에 직접 url경로를 변경하여 페이지가 새로고침 되면 전역상태값을 잃어버린다는 것이다.

처음 렌더링 시에는 페이지가 리렌더링되지 않아 posts전역 상태값이 남아있지만, url경로를 변경하게 되면 새로고침 되어 posts상태값이 초기화되기 때문에 그 다음부터는 post데이터를 가져오지 못한다. postPage에서는 서버에서 데이터를 가져오는 로직이 없기 때문이다. 서버와 Redux를 같이 사용하면서 혼동을 했는지 전역상태가 항상 저장되어 있을거라는 말도안되는 착각을 하고 있었다.. 전역 상태도 state기 때문에 새로고침 시 값이 초기화 된다.

 

해결 방법

1. 새로고침에 의해(경로 이동 등) 전역상태가 초기화 되어 post정보를 가져오지 못하는 의존성을 줄이기 위해

상세페이지에서도 데이터 통신을 해서 id값에 맞는 post 데이터를 가져오도록 하였다.

function PostPage() {
  const [post, setPost] = useState();

  // param.id로 post가져오기
  const { id } = useParams();
  const getPostData = async () => {
    const data = await getPostAxios(id);
    setPost(data);
  };

  useEffect(() => {
    getPostData();
  }, [post]);

 

2. 해당하는 post 정보가 없을 경우, 즉 해당 경로에 해당하는 페이지가 없을 경우, 에러일 경우의 처리를 해주어야 한다.

{/* url경로를 직접 입력시 일치하는 post 정보가 없을 경우 보여주는 문구 */}
      {!post ? (
        <StFlexCenter>
          <ErrorMessage>❗페이지 정보가 없습니다.</ErrorMessage>
        </StFlexCenter>
      ) : (
        <>
          <StPositionSec position={true}>

 

깨달은점

1. 전역 상태관리에 대한 개념, 리렌더링에 의한 state 초기화 등 의존성 여부에 따라 전역상태로 관리할 것 => posts, post, modal 등 

2. url경로 직접 입력시 페이지가 이동될 경우 전역 state가 초기화 되기 때문에 해당 컴포넌트는 따로 직접 데이터 요청하여 데이터를 가져오도록 한다.

3. Link와 useNavigate, url로 인한 라우터 경로 이동의 차이 => url로 이동 시 새로고침 된다.

4. 이벤트 위임 취소

5. 컴포넌트 구조를 잘 짜놓자. width와 height .. 상위 컨테이너에서 확실하게 크기를 정하지 않고 유동적으로 지정할 경우, 연속적으로 하위 컴포넌트에서 크기변경에 따른 문제 발생확률이 높다. 개선방법 생각해 보기