"렌더링 소품"대신 사용자 지정 후크 사용



멋지지만 때때로 React의 일부를 파악하기 어려운 것 중 하나는 다양한 구성 요소에서 상태 저장 논리를 재사용하는 것입니다. 필요할 때마다 특정 상태 저장 논리를 다시 작성하는 대신 이 논리를 한 번만 작성한 다음 필요한 모든 구성 요소에서 재사용하는 것을 모두 좋아합니다. 이를 가능하게 하는 일반적인 패턴은 "렌더링 소품"입니다.
렌더링 소품이 있는 구성 요소는 자체 렌더링 논리를 구현하는 대신 React 요소를 반환하고 호출하는 함수를 사용합니다. 이 구성 요소는 '컨테이너 구성 요소'라고 할 수 있는 반면 우리가 반환하는 React 요소 또는 구성 요소는 '프레젠테이션 구성 요소'라고 할 수 있습니다.


// example 1
<Container render={prop => (
 <Presentation {...props} />
)} />

// example 2
<Container children={prop => (
 <Presentation {...props} />
)} />

// example 3
<Container>
 {props => (
    <Presentation {...props} />
  )}
</Container>

위의 세 가지 예는 렌더링 소품 패턴을 구현합니다. 여기서 '컨테이너'는 프레젠테이션 구성 요소를 렌더링하는 컨테이너 구성 요소입니다. 컨테이너 구성 요소에서 재사용해야 하는 모든 상태 저장 논리를 넣을 수 있으며 필요한 경우 '업데이트 함수'와 함께 결과를 렌더링하는 다른 구성 요소로 전달할 수 있습니다. 간단히 말해서 "렌더링 소품"입니다.

대안은 무엇입니까?



컨테이너 대신 이 로직을 구현하고 '업데이트 함수'로 결과를 반환하는 사용자 정의 후크가 있다면 어떨까요? '업데이트 함수'란 컨테이너의 상태 또는 후크의 결과를 업데이트하는 함수를 의미합니다. 우리가 이것을 구현하는 방법은 우리가 여기에 있는 정확한 이유입니다. 렌더링 소품에 대한 공식 React 문서에서 찾은 "고양이와 쥐"예제를 사용해 봅시다. "render props"예제를 살펴보고 사용자 지정 후크를 사용하도록 리팩토링을 시도할 것입니다.

렌더 소품 예시



아래와 같이 마우스 움직임을 듣고 상태에서 포인터 위치를 설정하는 구성 요소가 있는 경우:

class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>

        {/*
          Instead of providing a static representation of what <Mouse> renders,
          use the `render` prop to dynamically determine what to render.
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

마우스의 위치에 따라 요소를 렌더링해야 하는 모든 구성 요소는 마우스 구성 요소로 렌더링할 수 있습니다. 마우스 포인터를 쫓는 고양이의 이미지를 렌더링하는 Cat 컴포넌트를 정의해 보겠습니다.

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: 
      mouse.y }} />
    );
  }
}

포인터 위치를 가져오기 위해 논리를 다시 작성할 필요는 없지만 다음과 같이 Mouse 구성 요소에서 이 논리를 확장할 수 있습니다.

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

이렇게 하면 마우스 위치를 소품으로 전달하는 Cat 구성 요소가 렌더링됩니다. 필요한 만큼 많은 구성 요소에서 논리를 재사용할 수 있습니다.

후크 대안



우리는 '마우스' 구성 요소를 제거하고 대신 마우스 논리를 구현하는 후크를 만들 것입니다.

export function useMouse(initialValue = {x:0, y:0}) {
  const [position, setPosition] = useState(initialValue);
  const handleMouseMove = (event) => {
    setPosition({
      x: event.clientX,
      y: event.clientY
    });
  }
  return [position, handleMouseMove];
}

우리는 방금 useMouse라는 후크를 정의했습니다. 사람들이 후크라는 것을 알 수 있도록 함수 이름이 'use'로 시작하는 것이 관례입니다. useMouse 후크는 마우스의 위치와 해당 위치를 업데이트하는 함수를 반환합니다. Cat 컴포넌트에서 이것을 어떻게 사용할 수 있는지 봅시다.

function Cat() {
  const [position, setMousePosition] = useMouse();

  return (
    <div style={{ height: '100%' }} onMouseMove={setMousePosition}>
      <img src="/cat.jpg" style={{ position: 'absolute', left: position.x, top: 
      position.y }} />
    );
    </div>
}

심플하다?..깔끔하다?..간결하다, 어떤 단어가 떠오르나요? 어쩌면 세 가지 모두. 움직일 때 마우스 위치를 가져와야 하는 구성 요소는 이 후크를 사용할 수 있습니다.
이 패턴을 사용하면 복잡한 반응 코드의 가독성과 유지 관리가 향상되며 매우 크고 깊게 중첩된 구성 요소 트리를 방지하는 데도 도움이 됩니다. 사용자 정의 후크를 생성하여 인증 상태, 사용자 정보 및 양식 처리 로직을 재사용할 수 있습니다. React에서 HOC(Higher Order Components) 대신 사용할 수도 있습니다.

좋은 웹페이지 즐겨찾기