Reputation: 362
I'm trying to put the div scroll with ref tag inside Dialog Material-UI Design I'm getting an error says Cannot read property 'scrollHeight' of undefined
If I use my code out of Dialog it works fine here's the example
All what I'm trying to do is to make the scroll div to start from the end
I did an example on Not working with Dialog
import React from 'react';
import { render } from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
}
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
componentDidMount() {
this.shoppingListContainer.scrollTop = this.shoppingListContainer.scrollHeight;
}
render() {
return (
<MuiThemeProvider>
<div id="scrolldiv">
<RaisedButton label="Alert" onClick={this.handleOpen} />
<Dialog
title="Dialog With Actions"
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<div>
<ul style={{
width: 115,
height: 100,
overflow: 'auto',
border: '2px black solid'
}}
ref={(shoppingListContainer) => { this.shoppingListContainer = shoppingListContainer; }}
>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
</Dialog>
</div>
</MuiThemeProvider>
);
}
}
render(<App />, document.getElementById('root'));
Upvotes: 3
Views: 10749
Reputation: 847
Here is a possible solution.
The refs actually work in a pattern, when you define a ref it is
assigned to the Global Execution Context this
. So that, you can use
them as this.YourRefName
. But these refs a re not assigned to
this
, until your component is rendered/mounted completely.
In your case, you are using a ref of the
<ul>
component as namedshoppingListContainer
. in the methodcomponentDidMount()
method of the root component of your project, After rendeing the intial view of your project, you can see the<ul>
component is not rendered yet, That's why the ref you provided is showing undefined.
In such cases you do apply module approach to your component hierarchy. Following is the running code as per your implementation:
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
class ListContainer extends React.Component {
scrollToBottom = () => {
this.listContainer.scrollTop = this.listContainer.scrollHeight;
}
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
render() {
return (
<ul style={{
width: 115,
height: 100,
overflow: 'auto',
border: '2px black solid'
}}
ref={(element) => { this.listContainer = element; }}
>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
}
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
return (
<MuiThemeProvider>
<div id="scrolldiv" ref='listC' >
<RaisedButton label="Alert" onClick={this.handleOpen} />
<Dialog
title="Dialog With Actions"
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<div>
<ListContainer />
</div>
</Dialog>
</div>
</MuiThemeProvider>
);
}
}
export default App;
In the code above, I broke the component structure, to make sure reactjs will access the ref, exactly when the component with ref definition is rendered.
It will actually make your approach easy to understand and maintain.
Upvotes: 3
Reputation: 175
This is happening because react is not able to find shoppingListContainer You can try this code, it worked for me.
import React from 'react';
import { render } from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
}
}
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
componentDidMount() {
let shoppingListContainer = this.refs.scrolldiv;
if (shoppingListContainer) {
shoppingListContainer.style.scrollWidth =
shoppingListContainer.style.scrollHeight;
}
}
render() {
return (
<MuiThemeProvider>
<div>
<RaisedButton label="Alert" onClick={this.handleOpen} />
<Dialog
title="Dialog With Actions"
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
<div className="shopping-list" refs="scrolldiv"
style={{
width: 125,
height: 100,
overflow: 'auto',
border: '2px black solid'
}}>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
</Dialog>
</div>
</MuiThemeProvider>
);
}
}
render(<App />, document.getElementById('root'));
Upvotes: 1