[아티클] UI = f(data, state)

5/17/2024

누구의 컴퓨터에서 실행될 것인가?

컴포넌트는 결국 코드입니다. 이 코드는 ‘누구의 컴퓨터에서 실행될 것인가?’가 중요합니다. 여기서 실행 가능한 컴퓨터는 2대입니다. 나의 컴퓨터와 당신의 컴퓨터, 이 둘 중 한 컴퓨터에서 실행될 것입니다.
 

당신의 컴퓨터에서 실행된다면

const Couter = ()=>{ const [count, setCount ] = useState(); return <div> <button onClick={()=>{setCount(prev => prev++)}}> Count: {count}</button> </div> }
이 컴포넌트에서 당신이 만약 버튼을 클릭한다면, 지연없이 즉시 카운트가 증가될 것입니다. 서버의 응답을 기다리거나, 추가로 데이터를 다운로드 받을 필요가 없습니다. 왜냐하면 당신의 컴퓨터에서 실행 중이기 때문이죠!
 
  • 버튼을 클릭하고 서버에 다음 출력을 요청하고 싶다면요?
    • 너무 느립니다. 즉각적인 피드백이 이루어지지 않아 사용자 경험을 떨어뜨릴 수도 있습니다
    • 예를 들어 링크 이동과 같이, 사용자가 앱의 다른 위치로 이동하고 있음을 알고 있어, 지연을 예상하는 경우에는 서버에 새 UI를 요청하는 것이 낫습니다. 유저는 기다릴 수 있으니까요.
 
그러나 만약, 슬라이더, 드래그, 탭 전환, 글 입력, 좋아요 클릭, 스와이프, 메뉴에 마우스 올리기, 차트 드래그 등 즉각적인 피드백이 최소한으로라도 있어야 하는 경우는 어떨까요? 서버에 다음 출력을 요청할 건가요?
  • User Interface 설계 측면에서 본다면
    • 지연시간이 짧고, 네트워크 왕복이 일어나지 않는 응답을 제공해야 합니다.
 

나의 컴퓨터에서 실행된다면

아래 PostPreview 컴포넌트는 어떻게 해당 게시글의 단어를 미리 알 수 있었을까요? 게시글의 단어 수를 요청한 내역도 없습니다. 바로 나의 컴퓨터, 서버에서 이미 데이터 전처리를 진행하였기 때문입니다. 그래서 당신은 정말 렌더링에 필요한 wordCount만 받아서 렌더링한 것이죠.
import { readFile } from "fs/promises"; import matter from "gray-matter"; export async function PostPreview({ slug }) { const fileContent = await readFile("./public/" + slug + "/index.md", "utf8"); const { data, content } = matter(fileContent); const wordCount = content.split(" ").filter(Boolean).length; return ( <section className="rounded-md bg-black/5 p-2"> <h5 className="font-bold"> <a href={"/" + slug} target="_blank"> {data.title} </a> </h5> <i>{wordCount} words</i> </section> ); }

UI = f(state)

현재 상태가 UI를 결정합니다. 상태가 변화하면 UI도 변경되어야 합니다. 이때의 상태는 클라이언트의 것이고, 코드 또한 클라이언트의 컴퓨터에서 실행됩니다. 예를 들면 <Couter />와 같이 사용자와 즉각적인 상호작용을 해야 하는 컴포넌트가 해당됩니다.
  • 물론! ‘초기 상태’를 활용하여 HTML을 생성하기 위해서, 서버에서도 해당 코드가 실행되긴 합니다. 그러나 서버는 count = 0만 알 뿐, 현재 상태를 모릅니다. 서버와 클라이언트가 서로 상태를 전달한다고 하면 너무 느리고, 항상 가능할 것이라는 보장도 없죠
 

UI = f(data)

data는 서버의 것이고, 함수 또한 서버에서만 실행됩니다. readFile과 같은 서버 전용 API는 클라이언트에서 사용할 수도 없습니다. <PostPreview />와 같이 데이터 전처리를 수행하는 컴포넌트가 해당됩니다.
 

현실은 UI = f(data,state)

현실의 개발에서는 state만, data만 활용하지 않습니다. 이 둘은 서로 섞이어 현재 상태를 나타내는 UI를 제공합니다.
⇒ 이것이 어떻게 펼쳐지고 있을지는 다음 아티클에서 계속하겠습니다!
 

Q. 클라이언트 컴포넌트와 서버 컴포넌트를 어떻게 분리하고 있나요? 자신만의 기준이 있나요?

Q. 클라이언트의 상태와 서버 데이터를 어떻게 분리하고 있나요? 자신만의 기준이 있나요?

 
©JIYOUNG CHOI, All rights reserved