Как получить высоту диалога в пользовательском интерфейсе Material, используя ref?

#reactjs #material-ui

#reactjs #материал-пользовательский интерфейс

Вопрос:

Я использую Material UI для своего проекта React, и я нахожусь в ситуации, когда я хочу получить высоту диалогового окна. Итак, я попытался сделать что-то вроде этого:

 import Dialog from '@material-ui/core/Dialog';

class MyDialog extends React.Component {
   constructor(props) {
      super(props);

      this.dialogRef = React.createRef();
   }

   render() {
      if (this.dialogRef.curent) {
         console.log(this.dialogRef.current);
      }

      return (
         <Dialog maxWidth='sm'
                 innerRef={this.dialogRef}
         >
            // Rest removed for brevity
         </Dialog>
      );
   }
}

export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(withLocalize(MyDialog)));
  

Теперь с помощью приведенного выше кода я вижу объект, напечатанный с помощью console.log(this.dialogRef) строки, и у него есть свойство с именем refs , которое является пустым объектом. Как я могу получить высоту Dialog в этом случае? Либо внутри MyDialog компонента, либо предполагая, что у меня есть другой вызываемый компонент, Main который вызывает MyDialog внутри своего метода рендеринга?

Пожалуйста, обратите внимание, что я использую "react": "^16.6.3" и "@material-ui/core": "^3.6.1" .

Ответ №1:

Я полагаю, что RootRef в этом случае найдет неправильный элемент DOM. Я думаю, вы хотите, чтобы div из компонента Paper внутри диалогового окна получал высоту. Вы можете сделать это, переопределив компонент для документа:

 const PaperComponent = ({ dialogRef, ...other }) => {
  return <div ref={dialogRef} {...other} />;
};
  
      <Dialog
        PaperProps={{ component: PaperComponent, dialogRef: this.dialogRef }}
      >
  

Вот модифицированная версия вашей песочницы: https://codesandbox.io/s/2vxz5lq1jr

Комментарии:

1. Спасибо, Райан, это кажется намного ближе к тому, чего я хочу достичь. Я вижу, вы используете useEffect для регистрации offsetHeight. Могу ли я каким-то образом сохранить высоту внутри переменной, чтобы я мог получить к ней доступ также из класса, который отображает диалоговое окно? Потому что, если я попытаюсь записать в консоль значение смещения внутри класса, оно выдает null при открытии диалогового окна и фактическое значение при его закрытии.

2. @terett Я думаю, что это вопрос времени. К открытию диалогового окна применяется переход, поэтому вам нужна некоторая задержка, прежде чем высота будет доступна.

3. @terett Вы могли бы попросить компонент Paper поместить высоту в контекст эффекта, чтобы передать ее чему-то более высокому в иерархии.

4. На самом деле мне даже не нужно передавать его чему-то более высокому. Я также выступаю style за PaperProps . Дело в том, что я хочу изменить стиль в зависимости от высоты диалогового окна. Итак, небольшая задержка может сработать, я думаю. Как я могу этого добиться?

5. Вот пример использования useLayoutEffect для этого: codesandbox.io/s/942ym6k964 . Поскольку вам не нужна ссылка в другом месте, это означает, что это можно еще больше упростить для использования useRef непосредственно в PaperComponent, а не передавать ссылку в качестве реквизита.

Ответ №2:

Вы можете использовать ref prop напрямую, начиная с Material-UI версии 4.0.0-alpha.3.

 function MyComponent() {
  const myRef = React.useRef();

  return <Dialog ref={myRef} />;
}
  

https://codesandbox.io/s/k0r6vj63l3

Комментарии:

1. Понятно, спасибо. Итак, нет способа сделать это в более ранней версии Material UI и полагаться на withStyles?

2. Вы можете использовать RootRef компонент с Material-UI v3.

3. Спасибо, кажется, это работает, если я окружаю <Dialog> внутри <RootRef> , но я не могу получить высоту. Он всегда показывает 0. Я пытался offsetHeight , clientHeight, даже getBoundingClientRect() . Все значения равны 0. Кроме того, при первом открытии диалогового окна ссылка равна нулю. Мне нужно закрыть и повторно открыть диалоговое окно, чтобы получить фактический элемент DOM. Но, как я уже сказал, даже тогда значения равны 0.

4. @OlivierTassinari Мой ответ показывает способ, который работает для версии v3, но, пожалуйста, сообщите, если считаете, что есть способ получше.

5. @terett Я думаю, что даже для версии 4 ссылка на диалоговое окно не предоставит нужный вам элемент DOM, поскольку он получает div для модального компонента, который, похоже, имеет полную высоту окна браузера, а не высоту содержимого диалогового окна.