28

I'm making list using onsenui and react. but I cannot call a bind from onchanged.

I couldn't figure out.... Does anyone can solve this?

this is my code. I'd like to call handlechanged method from input item. But then, Cannot read property 'bind' of undefined is raised.

export default class MainPage extends React.Component {


  constructor(props) {
      super(props);
      this.state = {
        selectedValue: "myself",
        destinations: ["myself","somebody"],
      };
  }


  handleChange(value) {
    this.setState({selectedValue: value});
  }

  renderRadioRow(row) {
    return (
      <ListItem key={row} tappable>
        <label className='left'>
          <Input
            inputId={`radio-${row}`}
            checked={row === this.selectedValue}
            onChange={this.handleChange.bind(this, row)}
            type='radio'
          />
        </label>
        <label htmlFor={`radio-${row}`} className='center'>
          {row}
        </label>
      </ListItem>
    )
  }

  render() {
    return (
      <Page renderToolbar={this.renderToolbar}>
        <p style={{textAlign: 'center'}}>
          test
        </p>

        <List
          dataSource={this.state.destinations}
          renderRow={this.renderRadioRow}
        />
      </Page>
    );
  }
}

3
  • Stack Snippets (the <> toolbar button that you used) are for runnable examples. Your example isn't runnable, so it should be in a code block (the {} toolbar button). But even better would be making it runnable, since Stack Snippets support ReactJS. Commented Sep 22, 2016 at 7:33
  • May be renderRadioRow function creates a new Context whose 'this' is used for binding onChange={this.handleChange.bind(this, row)}. Commented Sep 22, 2016 at 7:39
  • Is there a canonical answer to cannot read X of undefined? I keep seeing these questions and in 99% of the cases the reason is readily apparent - the error message says everything needed. You are accessing X from some variable that happens to be undefined. Suggested course of action - find out why and either prevent it or don't access X. Match to your needs. The rest of the questions are about the same happening in a third party library. In that case, it's usually a problem of not using it correctly. Suggested course of action - find if you've misconfigured it or are miscalling it. Commented Sep 22, 2016 at 7:39

2 Answers 2

32

https://facebook.github.io/react/docs/reusable-components.html#no-autobinding

No Autobinding

Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance. You'll have to explicitly use .bind(this) or arrow functions =>:

You can use bind() to preserve this

<div onClick={this.tick.bind(this)}>

Or you can use arrow functions

<div onClick={() => this.tick()}>

We recommend that you bind your event handlers in the constructor so they are only bound once for every instance:

constructor(props) {
  super(props);
  this.state = {count: props.initialCount};
  this.tick = this.tick.bind(this);
}

Now you can use this.tick directly as it was bound once in the constructor:

It is already bound in the constructor

<div onClick={this.tick}>

This is better for performance of your application, especially if you implement shouldComponentUpdate() with a shallow comparison in the child components.

export default class MainPage extends React.Component {


  constructor(props) {
      super(props);
      this.state = {
        selectedValue: "myself",
        destinations: ["myself","somebody"],
      };
      this.renderRadioRow = this.renderRadioRow.bind(this);
  }


  handleChange(value) {
    this.setState({selectedValue: value});
  }

  renderRadioRow(row) {
    return (
      <ListItem key={row} tappable>
        <label className='left'>
          <Input
            inputId={`radio-${row}`}
            checked={row === this.selectedValue}
            onChange={() => {
              this.handleChange(row);
            }
            type='radio'
          />
        </label>
        <label htmlFor={`radio-${row}`} className='center'>
          {row}
        </label>
      </ListItem>
    )
  }

  render() {
    return (
      <Page renderToolbar={this.renderToolbar}>
        <p style={{textAlign: 'center'}}>
          test
        </p>

        <List
          dataSource={this.state.destinations}
          renderRow={this.renderRadioRow}
        />
      </Page>
    );
  }
}

Sign up to request clarification or add additional context in comments.

6 Comments

I need to call this function with row value, can I put some values to this function?
Then use the arrow function onChange={() => handleChange(row)}
I tried () => handleChange(row) and () => this.handleChange(row). But both raised undefined handleChange error...
you need to bind this to renderRadioRow in order to call this.handleChange. I added an example
or handleChange = (row) => {} in your class definition. Then call it as onChange={handleChange(row)}
|
0

I dont know what value is passed in row , but you need to pass the render context in order to call that function and bind.

export default class MainPage extends React.Component {


    constructor(props) {
        super(props);
        this.state = {
            selectedValue: "myself",
            destinations: ["myself","somebody"],
        };
    }


    handleChange(value) {
        this.setState({selectedValue: value});
    }

    renderRadioRow(row,renderContext) {
        return (
            <ListItem key={row} tappable>
                <label className='left'>
                    <Input
                        inputId={`radio-${row}`}
                        checked={row === this.selectedValue}
                        onChange={this.handleChange.bind(renderContext, row)}
                        type='radio'
                    />
                </label>
                <label htmlFor={`radio-${row}`} className='center'>
                    {row}
                </label>
            </ListItem>
        )
    }

    render() {
        var renderContext=this;
        return (
            <Page renderToolbar={this.renderToolbar}>
                <p style={{textAlign: 'center'}}>
                    test
                </p>

                <List
                    dataSource={this.state.destinations}
                    renderRow={() => this.renderRadioRow(row,renderContext)}
                />
            </Page>
        );
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.