stackcafe123
stackcafe123

Reputation: 11

React.js and Material ui - handleclick function not working

I am trying to use react.js with material-ui. However, my event handlers do not seem to work.

For example, I tried playing around with the boilerplate material js file: (https://github.com/mui-org/material-ui/blob/master/docs/src/pages/demos/lists/NestedList.js )

The handleclick function does not work in my application (i.e. clicking on it does not collapse the list).

Th one major difference is that I used the code in a jsx file instead of js (however, changing the file to js does not solve the problem).

my code:

import React, {Component} from 'react'
import { List, ListItem, ListItemText, Collapse, Typography } from '@material-ui/core'
import { ExpandLess, ExpandMore } from '@material-ui/icons'
import { withStyles } from '@material-ui/core/styles';

const styles = theme => ({
  root: {
    width: '100%',
    maxWidth: 360,
    backgroundColor: theme.palette.secondary,
  },
  nested: {
    paddingLeft: theme.spacing.unit * 4,
  },
});

class NestedList extends Component {
  constructor(props){
    super(props);
    this.state = { open: true };
  };

  handleClick = () => {
    this.setState(state => ({ open: !this.state.open }));
  };

  render() {
    const { classes } = this.props;

    return (
      <div className={classes.root}>
        <List
          component="nav"
        >
          <ListItem>
            <ListItemText 
              disableTypography
              primary={<Typography type="subheadling" style={{ color: 'white' }}>Favourite</Typography>} 
            />
          </ListItem>
          <ListItem button onClick={this.handleClick}>
            <ListItemText 
                disableTypography
                primary={<Typography type="subheadling" style={{ color: 'white' }}>Playlists</Typography>} 
            />
            {this.state.open ? <ExpandLess style={{ color: 'white' }} /> : <ExpandMore style={{ color: 'white' }} />}
          </ListItem>
          <Collapse in={this.state.open} timeout="auto" unmountOnExit>
            <List component="div" disablePadding>
              <ListItem button className={classes.nested}>
                <ListItemText 
                  disableTypography
                  primary={<Typography type="subheadling" style={{ color: 'white' }}>{`p1`}</Typography>} 
                />
              </ListItem>
              <ListItem button className={classes.nested}>
                <ListItemText 
                    disableTypography
                    primary={<Typography type="subheadling" style={{ color: 'white' }}>{`p2`}</Typography>} 
                />
              </ListItem>
            </List>
          </Collapse>
        </List>
      </div>
    );
  }
}

export default withStyles(styles)(NestedList);

Update I suspect there is something wrong with the onClick Event since click is not listed as an event listener on the browser.

Upvotes: 0

Views: 3383

Answers (3)

stackcafe123
stackcafe123

Reputation: 11

Thanks to everyone for the help. I really appreciate the help from @Leogoesger and @CaseyC. Made me realize what's working in my code and where to debug for errors.

So the reason that the event handler didn't work is because I only rendered my Material-ui files on the server side and renderToString() stripped out all the event handlers.

I followed the instruction here: https://material-ui.com/guides/server-rendering/ and managed to get my App working.

Upvotes: 0

leogoesger
leogoesger

Reputation: 3820

Here is the working example of your code: https://codesandbox.io/s/k2nkj8705r

Neither of the following solutions might be what you are looking for, but here are a couple things you might want to watch out for:

Using handleEvent = () => {} is part of the babel-plugin-transform-class-properties. This gives you the implicit binding so you dont have to bind it youself. Otherwise, typically you will have to write differently like the following.

  handleClick {
    this.setState(state => ({ open: !this.state.open }));
  };

Then whenever you need to to use it, you have two options. Option 1 via bind. You can do that in your constructor.

this.handleClick = this.handleClick.bind(this);

Or(example onClick in a div). Another approach is to create a new function for every instance, not very efficient.

<div onClick={() => this.handleClick()}>Click me</div>

Although not a problem, setState is like this.

  handleClick = () => {
    this.setState({ open: !this.state.open });
  };

When calling setState, you just need to pass in an object.

Upvotes: 2

Edwin Harly
Edwin Harly

Reputation: 439

You forgot to bind your handleClick on your constructor, add this line to the bottom of your constructor this.handleClick = this.handleClick.bind(this);.

I just notice that you use handleClick = () => { ... }, if the babel was configured properly the binding won't be needed anymore, but let's try it and let me know if it's working or not

Upvotes: 1

Related Questions