简体   繁体   中英

using onChange with es6

I'm just learning. My 'onChange' event for a dropdown menu isn't working when converting code from ES5 to ES6 and I don't see where the problem is. I've looked through "Questions That May Have Your Answer", but nothing there. My app compiles, but there are errors from the Console. My suspicion is the 'onChange' attribute in the 'select' tag of Child.js. I'd appreciate any help offered. Here's my code:


index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Parent from './Parent';

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);

Parent.js

import React from 'react';
import Child from './Child';
import Sibling from './Sibling';

class Parent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {name: 'Frarthur'};
    this.changeName = this.changeName.bind(this);
  }

  changeName(newName) {
    this.setState({name: newName});
  }

  render() {
    return (
      <div>
        <Child onChange={this.changeName} />
        <Sibling name={this.state.name} />
      </div>
    );
  }
}

export default Parent;

Child.js

import React from 'react';

class Child extends React.Component {

  handleChange(e){
    let name = e.target.value;
    this.props.onChange(name);
  }

  render(){
    return (
      <div>
        <select
          id="great-names"
          onChange={() => this.handleChange()}>

          <option value="Frarthur">Frarthur</option>
          <option value="Gromulus">Gromulus</option>
          <option value="Thinkpiece">Thinkpiece</option>

        </select>
      </div>
    );
  }
}

export default Child;

Sibling.js

import React from 'react';

class Sibling extends React.Component {

  render(){
    let name = this.props.name;

    return (
      <div>
        <h1>Hey, my name is {name}!</h1>
        <h2>Don't you think {name} is the prettiest name ever?</h2>
        <h2>Sure am glad my parents picked {name}!</h2>
      </div>
    );
  }
}

export default Sibling;

Console

Uncaught TypeError: Cannot read property 'indexOf' of null
    at content.js:4186
Child.js:6Uncaught TypeError: Cannot read property 'target' of undefined
    at Child.handleChange (http://localhost:3000/static/js/bundle.js:32622:20)
    at onChange (http://localhost:3000/static/js/bundle.js:32644:30)
    at Object.executeOnChange (http://localhost:3000/static/js/bundle.js:24438:35)
    at ReactDOMComponent._handleChange (http://localhost:3000/static/js/bundle.js:24795:39)
    at Object.ReactErrorUtils.invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:16910:17)
    at executeDispatch (http://localhost:3000/static/js/bundle.js:16692:22)
    at Object.executeDispatchesInOrder (http://localhost:3000/static/js/bundle.js:16715:6)
    at executeDispatchesAndRelease (http://localhost:3000/static/js/bundle.js:16103:23)
    at executeDispatchesAndReleaseTopLevel (http://localhost:3000/static/js/bundle.js:16114:11)
    at Array.forEach (native)
Child.js:6Uncaught TypeError: Cannot read property 'target' of undefined
    at Child.handleChange (http://localhost:3000/static/js/bundle.js:32622:20)
    at onChange (http://localhost:3000/static/js/bundle.js:32644:30)
    at Object.executeOnChange (http://localhost:3000/static/js/bundle.js:24438:35)
    at ReactDOMComponent._handleChange (http://localhost:3000/static/js/bundle.js:24795:39)
    at Object.ReactErrorUtils.invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:16910:17)
    at executeDispatch (http://localhost:3000/static/js/bundle.js:16692:22)
    at Object.executeDispatchesInOrder (http://localhost:3000/static/js/bundle.js:16715:6)
    at executeDispatchesAndRelease (http://localhost:3000/static/js/bundle.js:16103:23)
    at executeDispatchesAndReleaseTopLevel (http://localhost:3000/static/js/bundle.js:16114:11)
    at Array.forEach (native)

You forgot to pass the event to handleChange function, Use this:

onChange={(e) => this.handleChange(e)}

or this:

onChange={this.handleChange.bind(this)}

Change your Child component like this

import React from 'react';

class Child extends React.Component {

  handleChange = (e) => {
    let name = e.target.value;
    this.props.onChange(name);
  }

  render(){
    return (
      <div>
        <select
          id="great-names"
          onChange={this.handleChange}>

          <option value="Frarthur">Frarthur</option>
          <option value="Gromulus">Gromulus</option>
          <option value="Thinkpiece">Thinkpiece</option>

        </select>
      </div>
    );
  }
}

export default Child;

this is not accessible for this.props.onChange(name); line if your handleChange . So make the function an es6 fat arrow function.

There are many ways to bind well your methods.

inside of constructor:

constructor() {
    this.addTask = this.addTask.bind(this)
    this.completeTask = this.completeTask.bind(this)
}

decorators (for example: link ):

@autobind
addTask(task) {
    /* ... */
    this.setState({ task });
}

class decorator (for example: link :

import autobind from 'class-autobind';
class MyComponent extends React.Component {
    constructor() {
        autobind(this);
    }
    addTask(task) {
        /* ... */
        this.setState({ task });
    }
}

as people before me said:

addTask = (task) => {
    /* ... */
    this.setState({ task })
}

I hope that might be helpful for some people. Make sure you bind your methods whenever you use them for example in events of input.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM