티스토리 뷰

React hook 중에 useImperativeHandle 이라는 훅이 있다. 이 훅은 forwardRef 를 사용해서 ref를 사용하는 부모 측에서 커스터마이징된 메서드를 사용할 수 있게 해준다.

예를 들어 아래처럼 정의하면,

function ParentComponent() {
  // inputRef라는 동아줄을 만들어서 자식에게 보낸다
  const inputRef = useRef();
  return (
    <>
          <FancyInput ref={inputRef} />
          <button onClick={() => inputRef.current.realllyFocus()}>포커스</button>
    </>
  )
}
function FancyInput(props, ref) {
  // 부모가 내려준 동아줄 ref에다가 이것 저것 작업을 한다
  // 부모는 이 로직에 대해 모르고, 위로 끌어올리지 않고도 그냥 ref.current로 접근하여 사용만 하면 된다
  useImperativeHandle(ref, () => ({
    reallyFocus: () => {
      ref.current.focus();
      console.log('Being focused!')
    }
  }));
  // ref는 input을 참조하고 있다. 
  return <input ref={inputRef} />
}

// ref를 컴포넌트에 달 때는 forwardRef로 감싼다
FancyInput = forwardRef(FancyInput)

원래 input 엘리먼트에는 reallyFocus라는 메서드가 없지만, useImperativeHandle 에서 정의하면 사용할 수 있다.

useImperativeHandle 의 첫 번째 인자로는 프로퍼티를 부여할 ref이고, 두 번째 인자는 객체를 리턴하는 함수이다. 이 객체에 추가하고 싶은 프로퍼티를 정의하면 된다. 예시에서는 reallyFocus 라는 메서드를 정의했고, 이 메서드를 호출하기 위해서는 사용처에서는 그 ref.current에 정의된 메서드를 호출하기만 하면 된다.

이렇게 할 때의 장점은 child component에 상태나 로직을 isolate할 수 있다는 점이다.

리액트에서는 데이터가 부모에서 자식으로만 흐르는데, 이렇게 단방향으로만 작동하는 방식을 회피해야 할 때는 Redux나 Context API 같은 것을 사용한다. 이런 것들을 사용하면 상태를 끌어올리지 않고도 부모에게 변경된 데이터가 적용되게 할 수 있다. 하지만 굳이 Redux나 Context API를 사용할 만큼의 일이 아닐 때 useImperativeHandle을 사용할 수도 있다. 상태나 로직들은 자식 컴포넌트가 갖고 있고, 부모 컴포넌트는 ref.current에서 필요한 프로퍼티를 가져오기만 하면 되기 때문이다.

하지만 기본적으로 리액트는 ref를 사용하는 것을 권장하지 않으므로 필요한 곳에서 선별적으로 사용하는 것이 좋겠다.

Ref

https://levelup.gitconnected.com/reacts-useimperativehandle-made-simple-81035a21eef0

https://reactjs.org/docs/hooks-reference.html#useimperativehandle

https://www.daleseo.com/react-forward-ref/

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함