실생활 예 - UseImperativeHandle

1. 잠깐만요...뭐죠?


useImperativeHandle를 사용하면 ref를 사용하여 자식 구성 요소에서 부모로 값과 함수를 전달할 수 있습니다.
거기에서 부모는 그것을 스스로 사용하거나 다른 자식에게 전달할 수 있습니다.

Note that you can only pass a ref as a prop to a child that wraps its component in forwardRef.



코드 예제는 이해에 있어 단어보다 훨씬 낫습니다. 그래서 여기에 그 중 하나가 있습니다.

// Parent Component
const App = () => {
  const ref = useRef();

  return (
    <div>
      <ComponentWithButton ref={ref} />
      <button onClick={() => ref.current.increment()}>another button</button>
    </div>
  );
};

// Child Component
const ComponentWithButton = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({increment}))

  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  return (
    <div>
      <button onClick={increment}>click</button>
      <h2>Count: {count}</h2>
    </div>
  )
})



위의 예에서 useImperativeHandleforwardRef 의 도움으로 상위 구성 요소의 카운트 변수를 변경하고 있습니다.

2. 왜?



React의 일반적인 패턴은 단방향 데이터 흐름을 갖는 것입니다.
양방향 데이터 흐름이 필요한 경우 Redux 또는 React context 와 같은 라이브러리를 사용할 수 있습니다.

그러나 어떤 경우에는 그것들을 사용하는 것이 단순히 과잉입니다.
이것은 useImperativeHandle가 들어오는 곳입니다.

이제 우리는 후크에 대해 어느 정도 이해했으며 이를 사용하고 싶을 때 실제 사례로 이동하겠습니다...

사용자가 자신의 정보 및 알림 기본 설정을 업데이트하고 편집할 수 있는 페이지Settings가 있습니다.

구성 요소에는 sections가 있으며 모든 섹션은 사용자와 관련된 데이터 변경을 담당하는 양식입니다(프로필 정보, 개인 정보 설정 및 알림 설정에 대한 섹션).

const Section = ({ name, text, fields, schema }) => {
  const { control, handleSubmit, reset, formState } = useForm({
    mode: 'onChange',
    defaultValues: fields.reduce((acc, field) => ({ ...acc, [field.name]: field.defaultValue }), {})
  });

  return (
    <section className={styles.section}>
      <Title text={text} />
      <form onSubmit={handleSubmit(onSubmit)}>
        {fields.map(field => (
          <Field key={field.name} {...field} control={control} />
        ))}
      </form>
    </section>
  );
};


모든 sectionSettings 구성 요소인 상위 구성 요소에서 렌더링됩니다.

const Settings = () => (
   <main className={styles.main}>
     {SECTIONS.map(section => (
        <Section key={section.name} {...section}  />
      ))}
   </main>
);


아마도 자식을 렌더링하는 부모 구성 요소는 모든 것이 괜찮을 것입니다. 하지만 전역 버튼을 클릭하여 모든 섹션의 제출 기능을 트리거하려면 어떻게 해야 할까요?
우리는 부모가 통제할 수 있는 방법이 필요할 것입니다. useImperativeHandle가 들어오는 곳입니다.
Section 구성 요소에 후크를 추가하고 정방향 참조로 래핑하여 Settings에서 참조를 전달할 수 있도록 합니다.

const Section = React.forwardRef(({ name, text, fields, schema },ref) => {
  const { control, handleSubmit, reset, formState } = useForm({
    mode: 'onChange',
    defaultValues: fields.reduce((acc, field) => ({ ...acc, [field.name]: field.defaultValue }), {})
  });


  useImperativeHandle(ref, () => ({
    submit() {
     handleSubmit(onSubmit)();
    }
  }));


  return (
    <section className={styles.section}>
      <Title text={text} />
      <form onSubmit={handleSubmit(onSubmit)}>
        {fields.map(field => (
          <Field key={field.name} {...field} control={control} />
        ))}
      </form>
    </section>
  );
});


후크의 도움으로 우리는 부모가 사용할 일종의 API를 만들 수 있습니다. 이 예에서는 우리가 호출할 수 있는 submit() 함수를 노출합니다.

이제 Settings 구성 요소는 다음과 같습니다.

const Settings = () => {
 const refProfile = useRef();
 const refNotifications = useRef();
 const refPrivacy = useRef();

// The SECTIONS object is a configuration object that will
// hold the refs among the rest of the data

 const onSubmitAll = () => {
    SECTIONS.forEach(({ ref }) => {
      ref.current.submit();
    });
  };

  return (
     <main className={styles.main}>
       {SECTIONS.map(section => (
       // The ref of each section i passed here in the spread 
       // operation.
          <Section key={section.name} {...section}  />        
        ))}
     </main>
  );
}


그게 다야! 우리는 해냈다!
더 복잡한 라이브러리를 가져오거나 사용하지 않고 컨트롤을 부모에게 다시 전달했습니다.




3. 결론



실망시키려는 의도는 아니지만 React는 이 후크를 사용하는 것을 권장하지 않습니다. (후크를 사용하지 않고 이 작업을 수행할 수 있는 다른 방법이 있을 가능성이 큽니다.)

전체 공개, 결국 구성 요소 구조 변경
하지만! 그럼에도 불구하고 거의 사용되지 않는 이 신비한 후크에 대해 배우는 것은 매우 재미있었습니다.

여러분도 즐거우셨길 바래요🙏🏼 읽어주셔서 감사합니다!!

좋은 웹페이지 즐겨찾기