Render Props Parttern
2024.06.08
공유 가능한 재사용 컴포넌트를 설계하기 위한 간단한 패턴으로 Render Props Pattern
이 있습니다.
1. Render Props Pattern는 언제 사용할까?
Input 컴포넌트의 경우 항상 해당 값의 상태(value)와 해당 상태를 컨트롤하는 함수(onChnage)가 필요합니다. 만약 특별한 과정을 거치지 않는다면 부모에서 상태를 관리하고자 할때에는 다음과 같이 상태를 Props로 넘겨서 사용하게 될 겁니다.
function Input({ value, setValue }) {
const onChange = (e) => setValue(e.target.value);
return (
<input
type="text"
value={value}
onChange={onChange}
placeholder="값을 입력 하세요."
/>
);
}
function App() {
const [value, setValue] = useState("");
return (
<div>
<Input value={value} setValue={setValue} />
<p>입력값 : {value}</p>
</div>
);
}
매번 onChnage와 value값를 지정하고 Props를 관리하는것은 여간 귀찮은 것이 아닙니다.
이러할때 Render Props Pattern
는 가장 간단한 해결책이 될 것입니다.
ContextAPI나 전역 상태 라이브러리를 적용하더라도 다시 다른 복잡한 리액트 패턴들로 설계를 해야하기에, 간단한 재사용 컴포넌트에서는 이방법이 가장 쉽습니다.
2. Render Props Pattern 적용하기
위에서 예시로 만든 파일을 Render Props패턴을 적용하면 다음과 같이 할 수 있습니다.
function Input({ render }) {
const [value, setValue] = useState("");
const onChange = (e) => setValue(e.target.value);
return (
<>
<input
type="text"
value={value}
onChange={onChange}
placeholder="값을 입력 하세요."
/>
{render(value)}
</>
);
}
function Double({ value }) {
return <p>두 배 값: {value * 2}</p>;
}
export default function App() {
return (
<div>
<Input
render={(value) => (
<>
<p>입력값: {value}</p>
<Double value={value} />
</>
)}
/>
</div>
);
}
이렇게 되면 <Input />
컴포넌트의 상태와 핸들링 함수를 만들어 줄 필요가 없고, 해당 상태의 값을 어떤 방식으로 화면에 나타낼지를 부모 함수에서 만들어 줄 수 있게 됩니다.
처음 코드의 부모 컴포넌트에서 모든 자식 컴포넌트의 상태가 있을때에는, 하나의 상태만 있더라도 재렌더링이 일어나게 됩니다. 하지만 각 컴포넌트별로 상태를 나눌수 있게 되고 불필요한 렌더링을 줄일 수 있습니다.
3. 결론
이 패턴은 간단하고 쉽게 유연한 설계를 하기에 좋은 패턴입니다. 로직이 복잡하면 1Prop Drilling와 같은 문제가 일어나서 다른 좋은 방법들을 사용하는게 유용할 수는 있지만
하지만 작은 단위의 컴포넌트에서 활용하기에는 매우 적합합니다.
Footnotes
-
Prop Drilling
: 데이터가 필요하지않지만, 전달에만 도움이되는 다른부분을 거쳐서 전달 (A->B->C->D, 사실 A->D만 렌더링해도된다.) ↩