2

I'm a total newbie with React and I was trying to build an app with React, but after many hours of trying, I couldn't figure out why the elements that I want to delete onClick aren't getting deleted.

There are 2 similar posts on this, they say that you would need to use independent keys for every element. I tried to do that, I even created a different variable and increment it after every use. It just deletes the top element of the list.

How it works - 1) I have an array which is stored with some names channels, and I get data with that names and save that data into another array renderAll.

2) After that I filter those on how I want to render them, and then I render them with a function renderCards(). It also renders a button which if clicked, should delete the channel from the channel array and the respective data from the renderAll array

3) It also have a input field from which you can add more channels.

What doesn't work - The delete button deletes the top element instead of the element which is clicked.

I have the app running without the delete functionality

var App = React.createClass({
    getInitialState() {
        return {
            status: 2
        }
    },
    changeStatus(i) {
        this.setState({
            status: i
        });
    },
    render() {
        return (
            <div>
                <header><h1>Twitch Streamers</h1></header>
                <Tabs status = {this.changeStatus} />
                <Cards status = {this.state.status} />
            </div>
        );
    }
});


const Cards = React.createClass({
    getInitialState() {
        return {
            renderAll: [],
            check: this.props.status,
            channels:  ["freecodecamp", "storbeck", "habathcx","meteos","RobotCaleb","noobs2ninjas","brunofin","comster404","cretetion","sheevergaming","TR7K","OgamingSC2","ESL_SC2"]
        };
    }, //AJAX REQUEST FUNCTION
    getData(last) {
        if(last === undefined) {
            for(let i =0; i<this.state.channels.length;i++) {
                let channel = this.state.channels[i];
                $.getJSON("https://api.twitch.tv/kraken/streams/" + channel, (data) => {
                    $.getJSON("https://api.twitch.tv/kraken/channels/" + channel, (logo) => {
                        if(data.hasOwnProperty(status) === false) {
                            if(data.stream === null) {
                                this.setState({
                                    renderAll: this.state.renderAll.concat([{channel: channel, url: `https://www.twitch.tv/${channel}`, status: 'offline', logo: logo.logo}])
                                });
                            } else {
                                this.setState({
                                    renderAll: this.state.renderAll.concat([{channel: data.stream.channel.name, url: `https://www.twitch.tv/${channel}`, current: data.stream.channel.game + ' - ' + data.stream.channel.status, status: 'online', logo: logo.logo}])
                                });
                            }
                        }
                    });
                })  
                .fail((jqxhr) => {
                    this.setState({
                        renderAll: this.state.renderAll.concat([{channel: channel, status: 'closed'}])
                    });
                });
            }
        } else {
            let channel = this.state.channels[this.state.channels.length - 1];
            $.getJSON("https://api.twitch.tv/kraken/streams/" + channel, (data) => {
                $.getJSON("https://api.twitch.tv/kraken/channels/" + channel, (logo) => {
                    if(data.hasOwnProperty(status) === false) {
                        if(data.stream === null) {
                            this.setState({
                                renderAll: this.state.renderAll.concat([{channel: channel, url: `https://www.twitch.tv/${channel}`, status: 'offline', logo: logo.logo}])
                            });
                        } else {
                            this.setState({
                                renderAll: this.state.renderAll.concat([{channel: data.stream.channel.name, url: `https://www.twitch.tv/${channel}`, current: data.stream.channel.game + ' - ' + data.stream.channel.status, status: 'online', logo: logo.logo}])
                            });
                        }
                    }
                });
            })  
            .fail((jqxhr) => {
                this.setState({
                    renderAll: this.state.renderAll.concat([{channel: channel, status: 'closed'}])
                });
            });
        }
    },
    componentWillMount() {
        this.getData();
    },
    componentWillReceiveProps(prop) {
        this.setState({
            check: prop
        });
    }, //DELETE FUNCTION THAT DOESN'T WORK
    delete(index) {
        let newArr = this.state.channels.slice();
        let newArrSecond = this.state.renderAll.slice();

        newArr.splice(index, 1);
        newArrSecond.splice(index, 1);

        this.setState({
            channels: newArr,
            renderAll: newArrSecond
        });
    }, //RENDER CARDS FUNCTION
    renderCards(i) {
        if(i === 0 || i.status === 0) {
            let cards = this.state.renderAll.map((item, i) => {
                if(item.status === 'online') {
                    return <div className="online cards" key={i}><img src={item.logo} width="30px" height="30px" /><a target="_blank" href={item.url}><h3>{item.channel}</h3></a><button className="cross" onClick={this.delete}>✕</button><p>{item.current}</p></div>
                }
            });
            return (
                cards
            )
        } else if(i === 1 || i.status === 1) {
            let cards = this.state.renderAll.map((item, i) => {
                if(item.status === 'offline') {
                    return <div className="offline cards" key={i}><img src={item.logo} width="30px" height="30px"/><a target="_blank" href={item.url}><h3>{item.channel}</h3></a><button className="cross" onClick={this.delete}>✕</button><p>Channel is offline</p></div>
                }
            });
            return (
                cards
            )
        } else if(i === 2 || i.status === 2) {
            let cards = this.state.renderAll.map((item, i) => {
                if(item.status === 'offline') {
                    return <div className="offline cards" key={i}><img src={item.logo} width="30px" height="30px" /><a target="_blank" href={item.url}><h3>{item.channel}</h3></a><button className="cross" onClick={this.delete}>✕</button><p>Channel is offline</p></div>
                } else if(item.status === 'online') {
                    return <div className="online cards" key={i}><img src={item.logo} width="30px" height="30px" /><a target="_blank" href={item.url}><h3>{item.channel}</h3></a><button className="cross" onClick={this.delete}>✕</button><p>{item.current}</p></div>
                } else {
                    return <div className="closed cards" key={i}><h3>{item.channel}</h3><p>Account Closed</p></div>
                }
            });
            return (
                cards
            )
        }
    },
    newChannel(i) {
        if(i.keyCode === 13) {
            this.setState({channels: this.state.channels.concat([i.target.value])}, function() {
                this.getData(1);
            });
        }
    },
    leave(i) {
        i.target.value = '';
    },
    render() {
        return (
            <div id="cards-inside">
                <input type='text' placeholder="+ Channel" onKeyDown={this.newChannel} onBlur={this.leave}/>
                <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
                    {this.renderCards(this.state.check)}
                </ReactCSSTransitionGroup>
            </div>  
        )
    }
});

ReactDOM.render(<App />, document.getElementById("container-second"));
0

2 Answers 2

1

Your index is always 0, because you do not pass it when you call delete.

Therefore it always deletes top element.

Inside the JSX bit where you render your X, you should do:

onClick={this.delete.bind(this, i)}

Or try

OnClick={() => {this.delete(i)} }

to pass the index of the card clicked.

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

2 Comments

It doesn't work and it also gives an extra error, "Warning: bind(): React component methods may only be bound to the component instance. See Cards"
I am sure the cause of the problem is that you need to pass the index. I updated answer, hope this helps.
0

In React, you don't really want to "delete" nodes like you'd do with jQuery.

Let's say you have a list of names in your initial state:

class MyComponent extends React.Component {
  state = {
    names: ['Foo', 'Bar', 'Git', 'Get']
  };
  [...]
}

In your render() method, you are rendering them inside a ul:

render() {
  const names = this.state.names.map(name => {
    return <li key={name} onClick={this.remove.bind(this, name)}>{name}</li>;
  });
  return <ul>{names}</ul>;
}

In your remove() method you will have:

remove(name) {
  this.setState({
    names: this.state.names.filter(cur => cur !== name)
  });
}

Now, every time you click on a name to remove it, you are removing the name from the names list, the component renders itself again, and the removed name will be removed from the DOM.

Working example:
http://codepen.io/FezVrasta/pen/MeWpzm?editors=0010

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.