简体   繁体   中英

How to change all value of items in a list in reactJS when onClick on an item

http://jsfiddle.net/adamchenwei/3rt0930z/23/ I tried apply solution from here react.js call parent function from child

But I encounter issue: 3VM606:43Uncaught TypeError: Cannot read property 'changeName' of undefined

Anyone knows why this is happening and how to fix it so that the onClick will change the name on every item, instead of just the one that got clicked on?

var items = [
    { name: 'Believe In Allah', link: 'https://www.quran.com' },
    { name: 'Prayer', link: 'https://www.quran.com' },
    { name: 'Zakat', link: 'https://www.quran.com' },
    { name: 'Fasting', link: 'https://www.quran.com' },
  { name: 'Hajj', link: 'https://www.quran.com' },
];

var ItemModule = React.createClass({
    getInitialState: function() {
        return { newName: this.props.name }
    },
    changeItsName() {
    this.props.changeTheName();
  },
    render() {
    //<!-- <a className='button' href={this.props.link}>{this.props.name}</a> -->
    return (
        <li onClick={this.changeItsName}>

        {this.state.newName}
      </li>
    );
  }
});

var RepeatModule = React.createClass({
    getInitialState: function() {
        return { items: [] }
    },
  changeName() {
    console.log('changed name');
    this.setState({ newName: 'Test' });
  },
    render: function() {

        var listItems = this.props.items.map(function(item) {
            return (
                <div>
          <ItemModule
            name={item.name}
            changeTheName={this.changeName.bind(this)}/>
        </div>
            );
        });

        return (
            <div className='pure-menu'>
                <h3>Islam Pillars</h3>
                <ul>
                    {listItems}
                </ul>
            </div>
        );
    }
});

ReactDOM.render(<RepeatModule items={items} />,                 
    document.getElementById('react-content'));

Thanks!

you have a scoping issue, within the map function this is referencing the map function not your react object. Either use es6 arrow syntax if you are using a transpiler or do the following

    var self = this;
    var listItems = this.props.items.map(function(item) {
        return (
            <div>
      <ItemModule
        name={item.name}
        changeTheName={self.changeName}/>
    </div>
        );
    });

The ES6 way of doing it would be:

var listItems = this.props.items.map((item) => 
    <div>
      <ItemModule
        name={item.name}
        changeTheName={this.changeName}/>
       </div>
    );

There is no need to do the this.changeName.bind(this) either, it actually makes react less performant when you do bindings within a components prop. see: https://daveceddia.com/avoid-bind-when-passing-props/https://daveceddia.com/avoid-bind-when-passing-props/

did you mean this -> http://codepen.io/dagman/pen/JRbyLj

const items = [{
    name: 'Believe In Allah',
    link: 'https://www.quran.com'
}, {
    name: 'Prayer',
    link: 'https://www.quran.com'
}, {
    name: 'Zakat',
    link: 'https://www.quran.com'
}, {
    name: 'Fasting',
    link: 'https://www.quran.com'
}, {
    name: 'Hajj',
    link: 'https://www.quran.com'
}, ];

const ItemModule = ({
    name,
    changeName
}) => (
    <li onClick={changeName}>
        {name}
  </li>
);

const RepeatModule = React.createClass({
    getInitialState: function() {
        return {
            newName: ''
        }
    },
    changeName() {
        console.log('changed name');
        this.setState({
            newName: 'Test'
        });
    },
    render() {
        const listItems = this.props.items.map((item) => {
            return (
                <ItemModule
                  name={this.state.newName || item.name}
                  changeName={this.changeName.bind(this)}
                />
      );
        });

        return (
            <div className='pure-menu'>
                <h3>Islam Pillars</h3>
                <ul>
                    {listItems}
                </ul>
            </div>
        );
    }
});

ReactDOM.render(
    <RepeatModule items={items} />,
    document.getElementById('react-content')
):

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