Lavios Lavios - 6 months ago 27
Javascript Question

How to delete elements with react? (Basic React query)

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"));

Answer

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.