Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

service(class)의 상태 변경을 context에서 인식할 수 있는 방법 #9

Open
Yena-Yun opened this issue May 11, 2023 · 16 comments

Comments

@Yena-Yun
Copy link

Yena-Yun commented May 11, 2023

islogin 여부에 따라 버튼과 todo 리스트가 보여지는 여부가 달라지도록
구현하는 과정에서 islogin 상태의 변화가
뷰에 바로바로 적용되지 않는 문제가 발생하였습니다.

image

위 화면에서 바로 새로고침을 하면
아래와 같이 logout 버튼과 todo 리스트가 잘 렌더링되지만

image

위 과정을 새로고침 없이 하는 방법이 있을까요?

현재 추측되는 원인은 islogin 변경 후
context 콘솔에서 islogin이 찍히지 않는 부분입니다

작성한 코드입니다
(빨간색 박스: 기존 실습 코드에서 추가로 작성한 부분)

AuthService.js

AuthContext.js

Auth.jsx

p.s. Auth 컴포넌트와 Todo 컴포넌트가 같이 렌더링되던 문제는 해결되었습니다! 제가 잘못 본 것 같았어요 😅

@powercording
Copy link

powercording commented May 11, 2023

음 아마 리랜더링 해주는 부분이 없어서 그런걸까요? 🤔

클래스의 셋스테이트가 useState 셋함수랑 같은건가요?

@Yena-Yun
Copy link
Author

그런 것 같은데 service에서의 상태 변화를 context에 인식시키는 방법을 모르겠어요 ㅠ.ㅠ
아니면 아예 이쪽 방향이 아닐 수도..

클래스 문법 찾아보니 useState랑 비슷한 거 맞는 것 같아요!
대신 무조건 this.setState로 변경시켜야 하고
컴포넌트 렌더링 되어야 트리거된다고 해서
onload 에 넣어봤는데 말 그대로 트리거만 되고 뷰는 변동 없더라고요 😂

@ohcmadah
Copy link

저는 AuthService가 컴포넌트로 사용되지 않아서 mount 되지 않는데, state를 사용하고 있어 나타나는 문제 아닐까 추측합니다!

저라면 아래와 같은 방식으로 구현할 것 같습니다.
AuthContext.js

import { createContext, useContext, useState } from "react";

const AuthContext = createContext(null);

export const useAuth = () => useContext(AuthContext);

export const AuthProvider = ({ children, authService, tokenRepository }) => {
  const [isLogin, setIsLogin] = useState(!!tokenRepository.get());

  const signin = (email, password) => {
    authService.signin.call(authService, email, password);
    setIsLogin(true);
  };
  const signup = authService.signup.bind(authService);
  const logout = () => {
    authService.logout.call(authService);
    setIsLogin(false);
  };

  return (
    <AuthContext.Provider
      value={{
        signin,
        signup,
        logout,
        isLogin,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

@Yena-Yun
Copy link
Author

오 AuthProvider 컴포넌트가 함수형이었네요..!
클래스형으로 해결해야 된다는 생각에 넘 집중하고 있었어요 😅 감사합니다 :)

혹시 call이랑 bind 메서드의 차이는 무엇인가요?

@ohcmadah
Copy link

@Yena-Yun
call의 경우 전달한 this, 인자들과 함께 함수를 호출합니다!
bind는 새로운 함수를 생성한다는 점에서 차이가 있습니다.

@powercording
Copy link

@Yena-Yun
제가 아는 선에서는 call은 this 적용시킬 객체를 명시적으로 지정해주는것이고,

Bind는 객체를 지정하는것은 call 과 같지만
리턴값이 해당 객체가 지정된 새로운 함수이기때문에 따로 호출하는 부분이 있어야 하는것으루 알고있습니다

@Yena-Yun
Copy link
Author

아 그래서 signin과 logout 안에서 call을 쓰신 거군요!

두 분 모두 답변 감사합니다 🥰

@Yena-Yun
Copy link
Author

Yena-Yun commented May 11, 2023

혹시 AuthService 내에서 Provider의 useState에 해당하는 로직을 처리할 수 있는 방법도 있을까요? 😳

@ohcmadah
Copy link

ohcmadah commented May 11, 2023

@Yena-Yun
class field에 isLogin을 두고 토큰 조작 코드 부분에서 바꿔주는 로직을 추가할 수도 있을 것 같습니다.
다만 화면에는 반영이 되지 않을 것으로 예상됩니다.

그러면 또 AuthContext나 Auth에 state를 두고 처리해야 하는데... 개인적으로 비효율적이라고 생각합니다 ㅠㅠ
더 나은 방법이 있는지 잘 모르겠네요 🥺

@powercording
Copy link

저도 처음떠오른생각은 프로바이더에서 스테이트 사용하는거였는데 다른방법은 딱히 떠오르는게 없더라구요.

혹시 서비스에서 스테이트 처럼 하고싶으신 이유가있을까여
저는 프로바이더쪽이 약간 훅처럼 더 어울릴거라생각해서

@Yena-Yun
Copy link
Author

@ohcmadah 아.. Context에 tokenRepository 추가로 넘기는 부분도 있고
service 안에서 함수 추가로 다 처리해서 어떻게든 해보고 싶었는데
렌더링에 영향을 주려면 최소 context를 거쳐야 하는 것일 수도 있겠네요 ㅠㅠ

@ohcmadah
Copy link

@Yena-Yun tokenRepository 추가로 넘기는 부분은 AuthService constructor에서 isLogin 초기화한 뒤, Context에서는 useState(authService.isLogin)으로 초기화해 줄 수도 있긴 하겠네요!

@Yena-Yun
Copy link
Author

@powercording 저 궁금했던 부분이 클래스형 문법 안에서 함수형의 useState처럼 state가 변경되면 리렌더링되는 로직을 처리할 수 있을지가 궁금했어요!

@Yena-Yun
Copy link
Author

@ohcmadah 이런 방법도 있네요..! 감사합니다 :))

@yeonuk-hwang
Copy link

AuthService 클래스에서 setState를 해주고 있긴 하지만, 이를 컴포넌트로 마운트하지 않았기에 AuthService와 그 자식들이 리렌더링 되지 않는 현상으로 보입니다. Provider에서 state.isLogin을 참조하고 있긴 하지만 이는 Provider의 state가 아니기에 변경된다고 리렌더링이 되지는 않고요,

의견 교환과정을 읽어보니 이 방식으로 코드를 작성한 이유가 AuthService에서 state의 처리까지 담당하고 싶어서인것으로 파악이 되는데 개인적으로 이 구조는 권장하지 않습니다. 왜냐하면 AuthService의 목적은 Auth에 관련된 기능들을 관리하는 것이지, React의 state까지 함께 처리하게 되면 AuthService에서 너무 많은 역할을 하게 되기 때문입니다.

@ohcmadah 님의 예시코드처럼 state를 관리하는 별도의 컴포넌트(예시 코드에서는 AuthProvider)를 두고, 거기서 state를 관리하는 역할, AuthService에서는 인증에 관련된 핵심 로직을 처리하는 역할로 분리해서 설계하는 방향이 좋을 것 같네요!

call, bind의 차이는 @powercording @ohcmadah님이 잘 설명해주신 것처럼 다 함수의 this와 관련된 메서드이지만, call은 this를 인자로 전달해서 바로 호출, bind는 인자로 전달한 this가 고정된 새로운 함수를 만든다는 차이점이 있습니다. call과 비슷한 메서드로 apply도 있는데 call과 apply는 둘 다 this를 전달하면서 함수를 호출한다는 공통점이 있지만, call의 경우는 여러 인자들을 "," 로 구분하고, apply의 경우에는 배열로 전달한다는 차이점이 있습니다.

const array = ["a", "b"];

[].push.call(array, 0, 1, 2);

console.info(array); // ["a", "b", 0, 1, 2]
const array = ["a", "b"];

[].push.apply(array, [0, 1, 2]);

console.info(array); // ["a", "b", 0, 1, 2]
const array = ["a", "b"];

const binded = [].push.bind(array)

binded(1,2,3)

console.info(array); // ["a", "b", 0, 1, 2]

@Yena-Yun
Copy link
Author

답변 감사드립니다! 🥰

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants