다시 액세스:useRef


심판이 뭐예요?
만약 당신이 나의 이전 문장을 읽었다면 useEffectuseLayoutEffect의 차이에 대해 다음과 같은 코드 부분을 보았을 것이다.
useEffect(() => {
  const greenSquare = document.querySelector(".App__square")
  greenSquare.style.transform = "translate(-50%, -50%)"
  greenSquare.style.left = "50%"
  greenSquare.style.top = "50%"
})

useLayoutEffect(() => {
  const greenSquare = document.querySelector(".App__square")
  greenSquare.style.transform = "translate(-50%, -50%)"
  greenSquare.style.left = "50%"
  greenSquare.style.top = "50%"
})
이러한 예에서 우리는 DOM에 직접 방문하여 요소(즉 .App__square)를 선택하고 조작했다. 이 요소는 React에서 anti-pattern으로 간주된다. 왜냐하면 virtual DOM을 통해 UI 상태를 관리하고 브라우저 버전과 비교하기 때문이다.그리고 이 프레임워크는 reconciling 두 모듈의 작업을 처리한다.그러나 어떤 경우, 우리는 이 규칙을 깨야 할 수도 있다.이것이 바로 refs의 출처다.
React 문서에서 refs을 사용하는 것이 초점 관리, 애니메이션 트리거, 제3자 라이브러리 사용을 포함하지만 과도하게 사용하지 말라고 경고했다.

Avoid using refs for anything that can be done declaratively. ~ React docs


React 응용 프로그램에서 refs을 어떻게 사용하는지에 대한 실제 예는 checkout my previous article about rebuilding a search UI에서 refs과 React 상하문을 참조하십시오.우리는 또한 이 시리즈의 다음 문장에서 상하 문장의 세부 사항을 소개할 것이다.
다음 절에서 우리는 useRef 갈고리와 그 문법을 더욱 자세하게 연구할 것이다.

useRef의 해부

...useRef is like a “box” that can hold a mutable value... ~ React docs

useRef 갈고리는 하나의 매개 변수만 받아들인다. 초기 값이다.유효한 JavaScript 값 또는 JSX 요소가 될 수 있습니다.다음은 몇 가지 예입니다.
// String value
const stringRef = useRef("initial value")

// Array value
const arrayRef = useRef([1, 2, 3])

// Object value
const objectRef = useRef({
  firstName: "Ryan",
  lastName: "Harris",
})
기본적으로 값을 ref에 저장하고 refcurrent 필드를 통해 액세스할 수 있습니다.예를 들어, 위의 코드 세그먼트에서 변수를 로그아웃하면 다음과 같은 결과가 표시됩니다.
console.log(stringRef)
// {
//   current: "initial value"
// }

console.log(arrayRef)
// {
//   current: [1, 2, 3]
// }

console.log(objectRef)
// {
//   current: {
//     firstName: 'Ryan',
//     lastName: 'Harris'
//   }
// }
제가 소개한 바와 같이 refs은 주로 DOM 액세스에 사용됩니다.다음은 ref 구성 요소의 컨텍스트에서 class을 정의하고 사용하는 예입니다.
class MyComponent extends React.Component {
  constructor() {
    super();
    this.inputRef = React.createRef();
  }

  render() {
    return (
      <div className="App">
        <input ref={this.inputRef} type="text" />
      </div>
    );
  }
}
갈고리를 사용하여 같은 일을 하기 위해서 우리는 useRef을 사용할 것입니다. 아래 코드 세션에서 보듯이:
function MyComponent() {
  const inputRef = useRef(null);

  return (
    <div className="App">
      <input ref={inputRef} type="text" />
    </div>
  );
}
이 예시들은ref를 어떻게 정의하는지 명확하게 설명하기를 바랍니다. 기억하십시오: refs은DOM 요소에 대한 '인용' 입니다. 이것은 바로 이름에 있습니다.refs에는 또 다른 흔치 않은 용례가 있다.ref의 값은 모든 자바스크립트 값일 수 있기 때문에 refs을 기본 데이터로 저장할 수도 있다.일반적으로 useState을 사용하여 비슷한 처리를 하지만, 때때로 불필요한 재렌더링을 피하고 싶지만 값을 캐시합니다.업데이트 상태의 값은 매번 다시 렌더링되고, 업데이트 refs은 구성 요소를 업데이트하지 않습니다.이것은 미묘하지만 중요한 차이이다.

실상
아래 섹션에서는 구성 요소가 다시 렌더링되지 않도록 useRef을 사용하여 DOM 요소와 스토리지 값에 액세스하는 방법을 두 가지 예로 더 잘 설명합니다.

DOM 요소 액세스
이 예에서 저는 작은 SearchInput 구성 요소를 구축했는데 이것은 useRef 갈고리를 사용하여 우리의 구성 요소가 보여준 <input /> 요소를 인용합니다.
이 특정한 예에서 우리의 SearchInput 부품은 autoFocus 도구를 사용하는데 이것은 우리가 <input />을 자동으로 마운트에 초점을 맞추기를 원하는지 여부를 결정한다.이를 위해서는 웹 API(즉 .focus())를 사용해야 하기 때문에 페이지의 HTML 요소를 직접 참조할 수 있어야 한다.
작업을 수행하려면 먼저 ref을 생성하여 요소에 할당해야 합니다.
// This instantiates our ref
const inputRef = useRef(null);

// Inside our return, we point `inputRef` at our <input /> element
<input ref={inputRef} type="search" className="SearchInput__input" />
현재 inputRef은 검색 입력을 가리키고 있으므로 inputRef.current에서 로그아웃하면 <input />을 볼 수 있습니다.
console.log(inputRef.current)
// <input type="search" class="SearchInput__input"></input>
이러한 연결을 통해 우리는 입력을 자동으로 브래킷에 초점을 맞추고, SearchInput 구성 요소를 여러 요소로 구성된 '엔진 덮개 밑' 으로 보이게 할 수 있다.자동 초점 맞추기 행위를 처리하기 위해서, 우리는 DOM을 그리기 전에 useLayoutEffect 갈고리를 사용하여 입력에 초점을 맞추어야 한다.
주의: useLayoutEffectuseEffect을 언제 사용하는지에 대한 더 많은 정보는 이 시리즈의 앞부분을 보십시오.
useLayoutEffect(() => {
  if (autoFocus) {
    inputRef.current.focus();
    setFocused(true);
  }
}, [autoFocus]);
inputRef.current.focus()을 호출하여 구성 요소의 <input />을 문서의 활성 요소로 설정합니다.또한 focused 후크에 저장된 useState 값을 업데이트하여 구성 요소를 설계했습니다.
const focusCn = focused ? "SearchInput focused" : "SearchInput";
마지막으로, 나는 모듈 안팎의 마우스 클릭에 따라 초점 상태를 업데이트하기 위해 useEffect 갈고리를 사용하여 이벤트 감청기를 추가했다.기본적으로 사용자가 SearchInput 내부를 클릭할 때 .focus()을 호출하고 focused 상태를 true으로 업데이트합니다.또는 사용자가 구성 요소 외부에서 클릭할 때 .blur()을 호출하고 focusedfalse으로 설정합니다.
useEffect(() => {
  function handleClick(event) {
    if (event.target === inputRef.current) {
      inputRef.current.focus();
      setFocused(true);
    } else {
      inputRef.current.blur();
      setFocused(false);
    }
  }

  document.addEventListener("click", handleClick);
  return () => {
    document.removeEventListener("click", handleClick);
  };
});
DOM 요소에 접근하는 것은 React 반모드 (위에서 말한 바와 같이) 이지만, 이 예는 refs의 유효한 예이다. 왜냐하면 우리의 목표는 .focus()을 사용해야 하기 때문에 HTML 요소에만 사용할 수 있기 때문이다.

스토리지 값을 다시 표시하지 않음
이 예에서 나는 useStateuseRef의 저장 값 간의 미세한 차이를 설명하고 싶다.
여기서 우리는 두 개의 단추가 있는 부분을 가지고 있는데, 그것들은 우리가 각각 refValue 또는 stateValue을 증가/감소시킬 수 있게 한다.페이지를 처음 불러올 때, 모든 부분에 무작위 16진수 값을 background-color으로 할당합니다.그때부터 저희 App 구성 요소가 다시 렌더링될 때마다 색의 변화를 보실 수 있습니다.
상태 값을 업데이트하면 렌더링이 다시 수행되므로 버튼 중 하나를 클릭할 때마다 stateValue 디지털 업데이트가 표시됩니다.하지만 refValue 버튼을 누르면 아무 일도 일어나지 않는다.이는 ref 값을 업데이트해도 어셈블리가 다시 렌더링되지 않기 때문입니다.refValue이 실제로 바뀌고 있음을 증명하기 위해 나는 두 단추의 console.log 처리 프로그램에 onClick 문장을 추가했다.refValue을 늘리거나 줄이면 UI가 올바른 수치로 업데이트되지는 않지만, stateValue을 변경하면 refValue이 업데이트되고 그 부분은 새로운 배경색을 갖습니다.이는 상태 값을 업데이트할 때 상위 구성 요소 ref이 가상 DOM과 브라우저 DOM이 서로 동기화되도록 조정해야 하기 때문에 App 섹션이 다시 나타납니다.이것은 응용 프로그램에서 불필요한 렌더링을 피하고 성능을 향상시킬 수 있는 좋은 전략입니다.

좋은 웹페이지 즐겨찾기