[리액트] 기초 개념 ref

AnSuebin·2022년 8월 18일
0

[리액트] 개념 정리

목록 보기
9/13

12. ref 속성값으로 자식 요소에 접근하기

리액트로 작업하다보면 실제 돔 요소에 직접 접근해야할 때가 있다.
예를 들어, 돔 요소에 포커스를 주거나 돔 요소 크기나 스크롤 위치를 알아야 하는 경우
ref 속성값을 이용하면 자식 요소에 직접 접근할 수 있다. 여기에서 자식 요소는 돔 요소나 컴포넌트일 수 있다.

1) 돔 요소에 접근하기

  • useRef 훅을 사용한다.
  • current 라는 요소는 실제 돔 요소를 가리키게 된다.
  • 돔 요소는 렌더링 결과가 실제 돔에 반영된 후에 접근할 수가 있기 때문에 부수효과 함수 안에서 접근을 할 수 있다.
  • ref 속성값은 아래와 같이 일반적인 컴포넌트에도 입력할 수 있다.
export default function App() {
  const inputRef = useRef();

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return (
    <input type="text" ref={inputRef} />
  )
}

2) 컴포넌트 접근하기

<Box ref={inputRef} />
  • 만약에 이 컴포넌트가 클래스형 컴포넌트라면 해당 컴포넌트의 인스턴스를 가리킨다. 따라서 current속성은 해당 클래스의 메서드를 호출할 수 있게 된다.

  • 함수형 컴포넌트는 인스턴스로 만들어지지 않지만 useImperativeHandle 이라는 훅을 사용하면 함수형 컴포넌트에서도 마치 클래스형 컴포넌트의 멤버 변수나 메서드에 접근하는 것처럼 함수형 컴포넌트의 변수나 함수를 외부로 노출시킬 수 있다.

  • 주의: 별다른 처리를 하지 않았다면 함수형 컴포넌트에 ref속성을 입력할 수 없고 아래와 같이 별도의 속성명을 사용하거나 forwardRef 를 사용해야 한다.

    • 별도의 속성명 사용하기
export default function App() {
  const inputRef = useRef();
  
  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return (
    <div>
      <InputAndSave inputRef={inputRef} />
      ...
    </div>
  )
}

function InputAndSave({ inputRef }) {
  return (
    <div>
      <input type="text" ref={inputRef} />
      ...
    </div>
  )
}
- forwardRef 사용하기 : 두 번째 매개변수로 ref 속성값을 받을 수 있다.
export default function App() {
  const buttonRef = useRef();

  return (
    <div>
      <Button ref={buttonRef} />
      ...
    </div>
  )
}

const Button = React.forwardRef(function ({ onClick }, ref) {
  return (
    <button onClick={onClick} ref={ref}>저장</button>
  )
})

3) ref 속성값에 함수 입력하기

  • useRef 속성을 사용하지 않고 ref 속성값에 함수를 입력할 수 있다.
  • ref 속성값에 입력된 함수는 해당하는 요소가 생성되거나 사라질 때 한 번씩 호출된다.
  • 생성될 때는 해당하는 요소의 레퍼런스가 넘어온다.
  • 사라질 때는 null 값이 넘어온다.
  • 따라서 요소가 생성될 때 setText(INITIAL_TEXT) 를 실행하여 text를 초기값으로 설정한다.
  • 이 코드에서는 버튼을 클릭할 때마다 showText를 보였다가 가렸다가를 반복하게 되는데, input 태그는 showTexttrue일 때만 보여지게 되므로 버튼을 클릭하여 showTexttrue가 되는 순간 setText(INITIAL_TEXT) 함수가 호출된다.
  • 문자를 입력할 때마다 setText 함수가 실행되고 컴포넌트가 다시 렌더링이 된다. 그런데 컴포넌트가 렌더링될 때마다 새로운 함수가 입력되면서 setText(INITIAL_TEXT)가 실행되어 초기화되기 때문에 text가 입력하는 텍스트로 제대로 업데이트 되지 않는 문제가 있다.
export default fuction App() {
	const [text, setText] = useState(INITIAL_TEXT)
    const [showText, setShowText] = useState(true)
 
    return(
    	<div>
        	{showText && (
            	<input type="text" ref={ref => ref && setText(INITIAL_TEXT}} value={text} onChange={e => setText(e.target.value} />
            )}
        <button onClick ={() => setShowText(!showText)}> 보이기 / 가리기 </button>
        </div>
    )
}

const INITIAL_TEXT = 'Hello world!'

4) useCallback 훅을 사용하여 함수를 고정하기

  • useCallback 훅의 메모이제이션 기능 덕분에 한 번 생성된 함수를 변화시키지 않고 계속해서 재사용할 수 있다.
  • 따라서 문자를 입력할 때마다 setText 함수가 실행되고 컴포넌트가 다시 렌더링 되어도 setText(INITIAL_TEXT)가 다시 실행되지 않는다.
  • ref가 새로 생성될 때 setText(INITIAL_TEXT)가 실행된다.
export default function App() {
	const [text, setText] = useState(INITIAL_TEXT)
    const [showText, setShowText] = useState(true)
       
    const setInitialText = useCallback((ref) => ref && setText(INITIAL_TEXT)}, []);
    
    return(
    	<div>
        	{showText && (
        <input
          type="text"
          ref={setInitialText}
          value={text}
          onChange={e => setText(e.target.value)}
        />
      )}   
      <button onClick={() => setShowText(!showText)}>보이기/가리기</button>
    </div>
  )
}

const INITIAL_TEXT = 'Hello world!';

참고
https://jess2.xyz/react/react-tip-0/#2-create-react-app-cra-%EC%9C%BC%EB%A1%9C-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0

profile
고객에게 명료한 의미를 전달하고, 명료한 코드를 통해 생산성 향상에 기여하고자 노력합니다.

0개의 댓글