Reputation: 2534
I am using material-ui^0.20 with react^16.2, and I have a problem when first showing up a Dialog
which embeds a Component
with too much content.
Here is a picture showing the problem :
And this is what should be showing up (and which is after closing the Dialog
and showing it up a second time, or after a window resize, etc.)
Here is some source code reproducing the problem (online demo here, and the source code):
import React, { Component } from 'react';
import { render } from 'react-dom';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
class BuggyComponent extends Component {
render() {
return <img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
}
}
class MyComponent extends React.Component {
state = {
open: false,
};
handleOpen = () => {
this.setState({open: true});
};
handleClose = () => {
this.setState({open: false});
};
render() {
return (
<div>
<RaisedButton label="Buggy Dialog" onClick={this.handleOpen} />
<Dialog
title="Dialog"
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<BuggyComponent />
</Dialog>
</div>
);
}
}
export default class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<MuiThemeProvider muiTheme={getMuiTheme({})}>
<MyComponent />
</MuiThemeProvider>
);
}
}
Is there something I can do to avoid this problem ? From what I could observe, not having a component inside a dialog, but the whole dialog as a component seems to correct this issue, but it's not very convenient, and not always possible.
Upvotes: 0
Views: 706
Reputation: 1430
What happens here is this: Popup opens, material ui tries to center it and to center it, it tries to figure out the height of the content. At this point, the image is not available, so the contents (the image) does not have a height.
Image loads. Image now has a height, but the dialog is already positioned so this does not help.
You could try pre-loading the image (which is basically what happens later when it's updated). A hack-ish way to do this would be something like this:
<RaisedButton label="Buggy Dialog" onClick={this.handleOpen} />
<img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" style={{width: '0', height: '0', visibility: 'hidden'}} />
This loads the image in an invisible img tag so the image is already loaded when the Dialog opens. The problem is that there is no guarantee that the image is loaded by the time the user clicks the button.
An alternative to this would be to detect when the image is loaded and then reposition the dialog. This works, but the downside is that once the image is loaded the dialog will jump, which may or may not be a problem.
class BuggyComponent extends Component {
reRender() {
this.props.dialog.forceUpdate();
}
render() {
return <img onLoad={() => this.reRender()} src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
}
}
<Dialog
ref="dialog"
repositionOnUpdate
title="Dialog"
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<BuggyComponent dialog={ this.refs.dialog} />
</Dialog>
A third option that only works when the height of the image is known is to explicitly set the height of the img-tag. This also prevents the need for a re-render when the image is loaded, but you will need to know the size beforehand.
A fourth option would be to change the function that opens the modal so that function preloads the image (if needed) before trying to open the modal.
The fifth and hopefully working option would be to make the custom component scrolling fixed size. This solves the problem of the unknown height, but requires you to determine what is a good fixed height which may or may not make sense depending on the content. To avoid having to worry too much about screen sizes, the height is expressed in vh.
class BuggyComponent extends Component {
render() {
return <div style={ {height: '70vh', overflow: 'scroll'} }>
<img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
</div>
}
}
Upvotes: 2