Общий модальный бутстрап реакции с использованием React ref

Я использую библиотеку реагирующих таблиц, и когда пользователь нажимает на значок расширения, я хочу, чтобы он открывал таблицу в модальном режиме (режимный режим загрузки). Мне нужно, чтобы модальное окно было универсальным и каждый раз получало другой компонент графика или даже обычный контент. Мне интересно, является ли это лучшей практикой для реализации этой функции. Я знаю, что не рекомендуется использовать React ref, и, согласно документации, диалог не является хорошим местом для использования этой стратегии. Но я не могу придумать другие варианты, которые позволят мне динамически передавать компонент графика или любой другой компонент. Хотелось бы услышать другие варианты.

Это мой модальный компонент:

const SiteModal = React.forwardRef((props, ref) => {
  return (
    <Modal {...props} size="lg" aria-labelledby="contained-modal-title-vcenter" centered ref={ref} 
            dialogClassName={classes.modalContainer}>
             <Modal.Header closeButton>
              <Modal.Title id="contained-modal-title-vcenter">
                Modal heading
              </Modal.Title>
            </Modal.Header>
           <Modal.Body>
            <h4>{props.children}</h4>
           </Modal.Body>
      </Modal>
     );
   });

Это мой родительский компонент, который также является элементом ref:

const CollapseEelemet = React.forwardRef((props, ref) => {
   const [open, setOpen] = useState(true);
   const [modalShow, setModalShow] = useState(false);

  return (
    <div className={classes.collapseWrapper}>
     <div onClick={() => setOpen(!open)} className={classes.collapseTitle} aria-controls={props.id}
         aria-expanded={open}>
        {props.title}
        <span onClick={() => setModalShow(true)} className="icon-launch"></span>
        **<SiteModal show={modalShow} onHide={() => setModalShow(false)}>
          {props.children}
        </SiteModal>**
     </div>
     <Collapse in={true}>
       <div id={props.id} ref={ref}>
         {props.children}
       </div>
     </Collapse>
   </div>
  );
});

А это мой главный родитель:

const Cost = (props) => {
   const renderMainGraph = () => {
       const ref = React.createRef();
       return (
          <div className={classes.mainChartWidget}>
           <CollapseEelemet ref={ref} id={constant.mainGraph.id} title={constant.mainGraph.title}>
              <LineChartFusion />
              <GroupColumnChart />
           </CollapseEelemet >
          </div>
         );
     };
 return (
   <div>{renderMainGraph ()}</div>
 );
}

person Shira    schedule 27.10.2020    source источник


Ответы (2)


Вы не используете ref правильно, React.createRef следует использовать только в компонентах класса.

const Cost = (props) => {
  const ref = useRef();
  return (
    <div className={classes.mainChartWidget}>
      <CollapseEelemet
        ref={ref}
        id={constant.mainGraph.id}
        title={constant.mainGraph.title}
      >
        <LineChartFusion />
        <GroupColumnChart />
      </CollapseEelemet>
    </div>
  );
}
person Dennis Vash    schedule 27.10.2020
comment
Вы правы, я только что прочитал об этом в документации React. Итак, какие у меня есть варианты? Предположим, я не хочу преобразовывать функциональный компонент в компоненты класса. - person Shira; 27.10.2020

Итак, я, очевидно, неправильно использовал Ref. Мне вообще не нужно его использовать (FYI Ref предназначены ТОЛЬКО для компонентов класса!). Я удалил все Refs и ForwordRef и просто передал компоненту произвольные дочерние элементы.

Вот как это выглядит сейчас:

Модальный компонент:

const SiteModal = (props) => {
  return (
    <Modal {...props} size="lg" aria-labelledby="contained-modal-title-vcenter" 
        centered ref={ref} dialogClassName={classes.modalContainer}>
         <Modal.Header closeButton>
          <Modal.Title id="contained-modal-title-vcenter">
            Modal heading
          </Modal.Title>
        </Modal.Header>
       <Modal.Body>
        <h4>{props.children}</h4>
       </Modal.Body>
  </Modal>
});

Разверните компонент:

 const CollapseEelemet = (props, ref) => {
    const [open, setOpen] = useState(true);
    const [modalShow, setModalShow] = useState(false);

return (
  <div className={classes.collapseWrapper}>
   <div onClick={() => setOpen(!open)} className={classes.collapseTitle} aria- 
    controls={props.id} aria-expanded={open}>
       {props.title}
      <span onClick={() => setModalShow(true)} className="icon-launch"></span>
       **<SiteModal show={modalShow} onHide={() => setModalShow(false)}>
           {props.children}
         </SiteModal>**
       </div>
        <Collapse in={true}>
         <div id={props.id}>
           {props.children}
         </div>
       </Collapse>
     </div>
   });

Верхний родительский компонент:

    const Cost = (props) => {
       const renderMainGraph = () => {
           return (
              <div className={classes.mainChartWidget}>
                <CollapseEelemet id={constant.mainGraph.id} title 
                  {constant.mainGraph.title}>
                    <LineChartFusion />
                    <GroupColumnChart />
                </CollapseEelemet >
              </div>
           );
        };
   return (
       <div>{renderMainGraph ()}</div>
        );
      }
person Shira    schedule 27.10.2020