구성 요소를 반환하는 후크에 대해 어떻게 생각하십니까?

13934 단어 react
사용할 때마다 인스턴스화할 상태 저장 논리가 필요한 UI 구성 요소 Modal이 있다고 가정해 보겠습니다.

const ComponentThatUsesModal = () => {
  const [visible, setVisible] = useState(false)
  const openModal = useCallback(() => setVisible(true), [setVisible])
  const closeModal = useCallback(() => setVisible(false), [setVisible])

  return (
    <div>
      Lorem Ipsum some text
      <Button onClick={openModal}>
        Show more information
      </Button>

      <Modal
        open={visible}
        onClose={closeModal}
      >
        <p>
          More information here
        </p>
      </Modal>
    </div>
  )
}


useModal 후크를 사용하여 상태 저장 논리를 재사용할 수 있지만 매번 모달(visible, closeModal)에 특정한 소품에서 useModal 및 Modal + 전달을 모두 가져와야 합니다. 이상적으로는 이러한 소품이 모달 자체 외부에서 사용되지 않기 때문에 노출을 피하는 것이 좋습니다(닫는 논리가 모달에서 완전히 처리되기 때문에). 다음과 같이 smth를 할 수 있다면 좋지 않을까요?

const ComponentThatUsesModal = () => {
  const {Modal, openModal} = useModal()

  return (
    <div>
      Lorem Ipsum some text
      <Button onClick={openModal}>
        Show more information
      </Button>

      <Modal>
        <p>
          More information here
        </p>
      </Modal>
    </div>
  )
}

// hooks/use-modal
const useModal = () => {
  const [open, setOpen] = useState(false)
  const openModal = useCallback(() => setOpen(true), [setOpen])
  const onClose = useCallback(() => setOpen(false), [setOpen])

  const Modal = useComponent(ModalBase, {open, onClose})

  return {
    openModal,
    Modal
  }
}


다음은 useComponent 후크의 구현입니다.

const useComponent = (Component, props = {}) => {
  const propsRef = useRef(props);
  propsRef.current = props;

  const componentRef = useRef((other) => {
    // It will use the very first Component passed into the hook
    return <Component {...propsRef.current} {...other} />;
  });

  return componentRef.current;
};


이것은 작동합니다. 이것을 확인하십시오sandbox. 그러나 내 걱정은 그것이 어떻게 작동하는지 이해하지 못한다는 것입니다. ref 를 통해 원래 바인딩된 소품을 추적하는 경우 구성 요소가 업데이트를 어떻게 알 수 있습니까? Rxjs의 Subject를 사용하는 두 번째 구현이 있습니다.

const useComponentV2 = (Component, bindedProps = {}) => {
  const propsSubjectRef = useRef(new Subject());
  useEffect(() => {
    propsSubjectRef.current.next(bindedProps);
  }, [bindedProps]);

  const componentRef = useRef((other) => {
    const [props, setProps] = useState(bindedProps);

    const currentPropsRef = useRef(props);
    currentPropsRef.current = props;

    useEffect(() => {
      const subscription = propsSubjectRef.current.subscribe((newProps) => {
        if (shallowEqual(newProps, currentPropsRef.current)) return;
        setProps(newProps);
      });
      return () => subscription.unsubscribe();
    }, []);
    // It will use the very first Component passed into the hook
    return <Component {...props} {...other} />;
  });

  return componentRef.current;
};

const shallowEqual = (obj1, obj2) =>
  Object.keys(obj1).length === Object.keys(obj2).length &&
  Object.keys(obj1).every(
    (key) => obj2.hasOwnProperty(key) && obj1[key] === obj2[key]
  );


첫 번째 구현과 비교하여 두 번 다시 렌더링하지만 적어도 다시 렌더링(상태 변경)하는 이유를 명확하게 알 수 있습니다. 구현에 대한 의견이나 우려 사항이 있는 사람이 있습니까? 우리는 그것이 프로덕션에서의 사용 사례에 대해 정말 잘 작동할 것이라고 생각하지만 너무 새롭고 이에 대한 문서를 본 적이 없기 때문에 우리가 발을 딛고 스스로를 쏠 수 있을지 걱정됩니다.

모든 응답에 감사드립니다!

좋은 웹페이지 즐겨찾기