This message was deleted.
# 질문
s
This message was deleted.
h
config 으로 service 주입합니다
머신을 어떤 단위로 쓰시느냐에 따라 조금씩 다를듯한데요
몇몇 로직은 use* hook 그대로 쓰고싶을 수 있는데 그럼 그냥 이벤트를 독립적으로 쏴야죠
아폴로 클라이언트 인스턴스를 넘겨주는건 이상한거같고요
Copy code
const [mutation] = useMutation(...);

const [state, send] = useMachine(machine, {
  services: {
    mutation,
  },
});
이렇게 주입합니다.
u
지금도
service
주입을 사용하긴 하는데요,
useLazyQuery
로 넘겨주려고 하면 타입 에러가 나는데
variables
는 따로 넘겨줘야 하는 걸까요?
h
타입에러나는 코드가 어떤거지요?
쿼리는... 서비스로 안쓰는걸 추천드려요 (마땅히 쓸 이유가 없고 관심사 분리가 애매해짐)
u
타입에러는
useMachine
에서 서비스로 레이지 쿼리(매개변수 포함된)를 넘길 때 발생하는데
h
...? 타입에러가 나면 잡으면 되죠
u
쿼리를 서비스로 넘기는 이유는 페이지네이션을 컴포넌트 상태로 가져갈 경우 컴포넌트와 상태로직이 결합하는 문제 때문에 로직을 분리하려고 했습니다.
h
타입에러를 올려주세요
페이지네이션을 컴포넌트 상태로 가져갈 경우 컴포넌트와 상태로직이 결합하는 문제 때문에 로직을 분리
잘 이해를 못했어요 ㅠㅠ
u
제가 잘 설명을 못해서 죄송한데 ㅠㅠ 캐시가 없는 페이지네이션을 하려면 컴포넌트 상태(
useState
) 로 관리하게 되면 컴포넌트 내부에
fetchMore
를 하고 페이지네이션 상태를 업데이트하는 코드가 들어가는데 컴포넌트와 로직을 분리하면 좋으니까 이걸 분리하려고 해여 타입에러는 지금 보고 잇습니당
예를 들면 다음과 같은 코드입니다..
Copy code
const ExampleComponent = () => {
  const loadMore = () => {
   ...endCursor 와 hasNextPage 를 체       크하고 컴포넌트의 페이지네이션 데이터를 업데이트 하는 로직
} // loadMore 를 분리하고 싶음
}
h
캐시에 대한 부분을 쿼리에 양도한 이상 무조건 분리하는게 좋은지는 생각해볼 여지가 있고요, fetchMore랑 page 상태 정도 보관하실거같은데 (context가 필요하다면...? 애초에 필요가 없을수도 있음) • 쿼리가 서비스의 제어를 받음 • 서비스가 쿼리를 이벤트로 받음 동기화를 둘 중에 하나로 갑니다
fetchMore 호출하면
pageInfo 가 갱신되죠?
어렵게 안하셔도 "서비스가 쿼리를 이벤트로 받음" 이걸로 충분히 느슨하게 동기화가 되는데
u
그쳐 인피니트 스크롤이 동작하면서
pageInfo
가 업데이트 되고 그거 기반으로 재쿼리해서 페이지네이션 상태 업데이트 하는 로직입니당
h
fetchMore 를 서비스로 넣고
pageInfo 를 메시지로 넣으시면 최종적으로는 동기화되는걸 기대할 수 있습니다
Copy code
React.useEffect(() => {
  send('PAGE_UPDATED', { pageInfo });
}, [send, pageInfo]);
이거만 있어도 머신 맥락을 컴포넌트랑 동기화할 수 있어요
u
그리고 머신 컨텍스트에 페이지네이션 상태값을 저장하는 거군여
h
뭐 로직을 태우던 이펙트를 태우던 그건 자유롭겠죠
무슨 일이 일어났는지 알려주면, 다음에 무엇을 해야하는지 통보해줍니다
제어를 조금 느슨하게 풀어보세요
둘이 의존성이 너무 강결합되면 안좋습니다
u
컴포넌트-머신의 결합 말씀하시는 건가여?
h
u
음 그러면
fetchMore
만 서비스로 넘긴다면 처음에 가져오는 데이터는 그냥
useQuery
에 있는 걸 쓰나여 아니면 컨텍스트에 다시 넘겨줘야 하나요? 여기가 뭔가 이상했어여
h
데이터가 필요한가요?
필요하면 그것도 이벤트로 보내던가 하시죠
suspense 가 있으면 더 깔끔한데 안쓰실테니까
send('INIT', { initialData })
u
데이터를 받아서 그걸 다시 머신 컨텍스트로 보내는게 뭔가 중복 같았어여…
h
"머신 컨텍스트로 보낸다" 는 아닙니다
u
머신이 로딩/성공/실패 상태를 가져야하는데
useQuery
의 결과값에 따라 이걸 다시 이벤트로 머신한테 주는게 뭔가 이상한다고 해야 하나
h
컨텍스트에 뭘 쓰는지는 결국 동작 디테일에 불과하고
컴포넌트는 그걸 알필요가 없어요
그건 로직에 따라 다른데 뭘 원하시는지에 따라
u
Copy code
useEffect(() => {
  if (loading) {
    send(LOADING)
  }
}, [loading]);
그럼 이런 코드는 valid 한가여?
h
어쨋든 핵심은 이벤트-사이드이펙트
사이드 이펙트 제어가 머신에서 하는게 더 유리하기 때문에
그런 부분들을 위임한다고 보시면 될듯
네 valid 해요
u
중복이라고 생각했는데 사이드 이펙트 위임이라는 측면에서 보면 맞는것 같긴 하네요
h
if (loading) 분기는 지우셔도 됩니다
디테일은 신경 안쓸수록 머신 가치가 높아지겠죠
어차피 transition schema 에 따라 deterministic 하게 제어될 것이기 때문에
컴포넌트에서 역할을 온전히 넘겨주면 분기문같은거도 대부분 필요없습니다
그리고 동기화는 apollo cache 로 부터 전파 받아서 자동으로 동기화가 될테구요
요컨데
이벤트를 쏘고, 세부사항은 잊어버리면 됩니다
깔끔하죠?
데이터를 주고받는게 아니에요
요청-응답도 아니고요
u
그럼 제가 이해한 바는 1. 첫 쿼리는 로딩/성공/실패에 따라 머신에 이벤트로 쏴줌 2. 이후
fetchMore
service
로 사용된다음 해당 서비스가 invoke 되면서 알아서 상태 전환 여기서 컴포넌트는 머신에 대해 알 필요 없고 이벤트만 쏴주면 됨 (컴포넌트-로직 분리의 핵심) 이렇게 되는데 맞게 이해한 걸까여?
아폴로 캐시는 안 쓰니까 여기서 캐시 동기화는 신경 안서도 될것 같아여
h
로딩/성공/실패에 따라
여전히 디테일이네요
아폴로 캐시는... 안쓴다는게 어떤의미인지
useQuery 를 아예 안쓴다는 의미인가요
u
fetchPolicy: no-cache
입니다
h
...;;;;
u
왜그러시져??
h
일단 그거랑도 상관이 없는걸로 알고있는데
필요하면 재요청이 알아서 날라갈테니 신경 안써도 되는건 동일합니다
u
근데 로딩/실패/성공이 여전히 디테일이라는 말씀이 이해가 안돼요 ㅠㅠ
왜 디테일이죠 저게 각각 다른 상태아닌가여?
h
쿼리는 캐시 정책이랑 무관하게 원래 imperative하게 쓰는 물건이 아니에요
아키텍처를 한 번 보셔야할듯
u
아폴로 문서는 거의 다 읽었어여…
h
그 상태를 구분하는건 머신이 할일이죠
그니까
u
머신이 그걸 구분하려면 현재 아폴로의 fetching 상태가 어때야 하는지 알아야 하지 않나요?
머신이 알아서 로딩/실패/성공을 구분할 수는 없지 않나여? 클라 인스턴스도 안받고 요청은 컴포넌트에서 하는데?
h
Copy code
React.useEffect(() => send('LOADING_CHANGE', loading), [loading]);React.useEffect(() => send('DATA_CHANGE', data), [data]);React.useEffect(() => send('ERROR_CHANGE', error), [error]);
이것만 있어도 머신에 주어진 맥락은 충분하고
u
어 제가 말한게 저건데 저걸 디테일이라고 말씀하신 줄 알았네요
h
아니
React.useEffect(() => send('RECIVED_RESULT', result), [result]);
만 있어도 됨
u
로딩/실패 없이여?
h
물론 아폴로 타입정의가 좀 구려서 쪼개면 좋긴 하겠습니다만
result 안에 들어있죠
result = { data, error, loading } 이니
u
아 그럼 머신이 result 받아서 알아서 상태 분기요?
h
할수있죠
역할 나누기 나름
그리고 서비스는 mutation, fetchMore 같은 사이드이펙트성만 씁니다
u
그럼 전체적으로 아폴로 요청 -> 이펙트로 머신에 이벤트 전송 -> 머신이 알아서 상태 분기, 쿼리는 imperative 말고 declarative 하게 사용 이거죠?
h
쿼리는 신경쓸 필요가 없어요 호출하면 알아서 캐시관리자(이 경우는 아폴로)에 의해 변경 전파가 일어나기 떄문에
u
감사합니다. 근데 아폴로 문서 불친절한 부분이 좀 있더라구여 자세히 써주면 좋았을 텐데
h
사실 쿼리 요청도 직접 제어하는것 보단 컴포넌트 단위로 다루는게 적절하다고 생각하는데
u
컴포넌트 단위 = colocated fragment 인가요?
h
아뇨
u
그럼 컴포넌트 단위의 쿼리는 뭔가여?
h
쿼리를 밖에서 하는게 아니라 필요한 컴포넌트에서 하고 (요청단위를 묶으려면 프래그먼트를 쓸 수 있겠죠) 제어는 부모 컴포넌트가 담당하는 식이죠
(외부에 있는 독립적인 서비스가 아닌)
로딩 제어는 UI 맥락에 의존적이거든요
물론 앱을 통째로 거대한 상태머신으로 다루는것도 유효한 접근이긴 한데
Apollo 랑 역할 나누기가 굉장히 애매해요
u
지금은 쿼리 + 머신을 동일한 컴포넌트에서 하려고 하는데 여기서 머신을 부모로 올린다는 건가요?
h
쿼리를 그냥 useQuery 쓰셔도 될것같다 였습니다
u
지금도 useQuery 쓰고 있어서 fetchMore 만 서비스로 보내보겠습니다