Написание ловушки React для обработки видимости нескольких div-ов при щелчке мышью - PullRequest
0 голосов
/ 18 февраля 2019

Только начал узнавать о Перехватить хуки , но я не могу понять, возможно ли написать простой хук (или я должен использовать какой-то другой подход, например useEffect вместе с useState) вчтобы контролировать видимость нескольких элементов, нажимая на разные кнопки на странице.

Допустим, у меня есть простое приложение с 2 кнопками и 2 "модальными" окнами:

const App = () => {
  const [firstModalOpen, toggleFirstModal] = useState(false);
  const [secondModalOpen, toggleSecondModal] = useState(false);

  return (
    <div>
      <button onClick={() => toggleFirstModal(true)}>Open First Modal</button>
      <button onClick={() => toggleSecondModal(true)}>Open Second Modal</button>

      <FirstModal
        {...props}
        show={firstModalOpen}
        toggleModal={toggleFirstModal}
      />

      <SecondModal
        {...props}
        show={secondModalOpen}
        toggleModal={toggleSecondModal}
      />
    </div>
  )
}

const FirstModal = (props) => {
  const { toggleModal, ...rest } = props;

  return (
    <Modal
      { ...rest }
      show={firstModalOpen}
      onHide={() => props.toggleModal(false)}
    >
      First modal content...
    </Modal>
  )
}

const SecondModal = (props) => {
  const { toggleModal, ...rest } = props;

  return (
    <Modal
      { ...rest }
      show={secondModalOpen}
      onHide={() => props.toggleModal(false)}
    >
      Second modal content...
    </Modal>
  )
}

// state hook attempt

const useToggleModal = () => (init) => {
  const [show, setToggleModal] = useState(init);
  const toggleModal = () => setToggleModal(!show);
  return { show, toggleModal };
};

Так как ониreact-bootstrap модальные окна, они используют свойства show и onHide для определения / обработки видимости, и мне нужно пропустить rest проп, чтобы избежать некоторых побочных эффектов.
Если бы яиспользуя мою попытку подключения в моем приложении, я бы обрабатывал оба модала при любом нажатии кнопки, поэтому мне пришла в голову идея передать строку (обеим кнопкам и модалам), которая бы указала, какой именно модал обрабатывать, но этот подход длякакая-то причина выглядела немного неправильно.

Есть ли в React более "умный" способ обрабатывать это внутренне, а не передавать строки?

1 Ответ

0 голосов
/ 18 февраля 2019

Если у вас есть несколько модалов, и только один из них должен открываться одновременно, то вы должны использовать одно состояние, в котором хранится информация о том, какой модальный режим открыт, что-то вроде строки, имеющей идентификатор модального окна.Однако, если вы хотите открыть несколько модалов, вы должны хранить isOpen prop по-другому

. В первом случае вы должны написать свой код как

const App = () => {
  const [openModal, toggleModal] = useState('');

  return (
    <div>
      <button onClick={() => toggleModal('first')}>Open First Modal</button>
      <button onClick={() => toggleModal('second')}>Open Second Modal</button>

      <FirstModal
        {...props}
        show={openModal === 'first'}
        toggleModal={toggleModal}
      />

      <SecondModal
        {...props}
        show={secondModalOpen}
        toggleModal={toggleModal}
      />
    </div>
  )
}

const FirstModal = (props) => {
  const { toggleModal, ...rest } = props;

  return (
    <Modal
      { ...rest }
      show={firstModalOpen}
      onHide={() => props.toggleModal('first')}
    >
      First modal content...
    </Modal>
  )
}

const SecondModal = (props) => {
  const { toggleModal, ...rest } = props;

  return (
    <Modal
      { ...rest }
      show={secondModalOpen}
      onHide={() => props.toggleModal('second')}
    >
      Second modal content...
    </Modal>
  )
}

Во втором случае это будет так, как выВы написали в своем примере, единственная оптимизация, которую вы можете сделать для второго случая, - это сохранить массив модальных объектов и динамически их визуализировать или позволить каждому модальному обрабатывать свои собственные состояния переключения и использовать useImperativeHandle для предоставления методов, к которым родитель может обращатьсядочерние модалы типа

const App = () => {
  const firstRef = useRef(null);
  const secondRef = useRef(null);

  return (
    <div>
      <button onClick={() => this.firstRef.current.toggleModal()}>Open First Modal</button>
      <button onClick={() => this.secondRef.current.toggleModal()}>Open Second Modal</button>

      <FirstModal
        {...props}
        ref={firstRef}
      />

      <SecondModal
        {...props}
        ref={secondRef}
      />
    </div>
  )
}

const FirstModal = forwardRef((props, ref) => {
 const { showModal, toggleModal } = useToggleModal(false, ref);

  return (
    <Modal
      { ...rest }
      show={showModal}
      onHide={toggleModal}
    >
      First modal content...
    </Modal>
  )
})

const SecondModal = forwardRef((props, ref) => {

  const { showModal, toggleModal } = useToggleModal(false, ref);
  return (
    <Modal
      { ...props }
      show={showModal}
      onHide={toggleModal}
    >
      Second modal content...
    </Modal>
  )
})

// state hook attempt

const useToggleModal = (init, ref) => {
  const [show, setToggleModal] = useState(init);
  const toggleModal = () => setToggleModal(!show);
  useImperativeHandle(ref, () => ({
    toggleModal
  }))
  return { show, toggleModal };
};
...