I have icons in a table setup so that when an icon is clicked, a different icon is rendered. Now this works fine but I want to re-render a different icon for that specific row in the row that I clicked as opposed to re-rendering a different icon in every row. No idea as to how I would go about doing this. Here is my code:
import React from 'react';
import StarBorder from '@material-ui/icons/StarBorder';
import Star from '@material-ui/icons/Star';
import axios from 'axios';
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
starIcon: true,
data: [],
}
}
componentDidMount() {
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=true')
.then(res => {
const data = res.data;
this.setState({ data: data})
})
}
handleClick = () => {
this.setState(prevState => ({
starIcon: !prevState.starIcon
}));
}
render() {
return (
<div>
<table border="1">
<thead>
<tr>
<td>Rank</td>
<td>Name</td>
<td>Price</td>
</tr>
</thead>
<tbody>
{this.state.data.map((n) => {
return (
<tr>
<td> <span onClick={() => this.handleClick()}> {this.state.starIcon ? <StarBorder/> : <Star /> } </span> </td>
<td>{n.name}</td>
<td>{n.current_price}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
export default Test;
To update our state, we use this. setState() and pass in an object. This object will get merged with the current state. When the state has been updated, our component re-renders automatically.
In your column array that you pass into react table you need to create a button who's onClick function takes a callback to edit your data to add an isEditing: true so you will handle turning the row to edit mode from outside of the table.
React will then look at the virtual DOM, it also has a copy of the old virtual DOM, that is why we shouldn't update the state directly, so we can have two different object references in memory, we have the old virtual DOM as well as the new virtual DOM.
The way I see it, you need to either duplicate your starIcon boolean in an array that has the same length as your data array, or integrate your boolean in your data array. Here's a proposition for the second option :
import React from 'react';
import StarBorder from '@material-ui/icons/StarBorder';
import Star from '@material-ui/icons/Star';
import axios from 'axios';
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
}
}
componentDidMount() {
axios.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=true')
.then(res => {
const data = res.data;
this.setState({ data: data.map(x => ({...x, starIcon: true}) ) })
})
}
handleClick = (i) => {
this.setState(prevState => ({
data: prevState.data.map((x, key) => (key === i ? {...x, starIcon: !x. starIcon} : x) )
}));
}
render() {
return (
<div>
<table border="1">
<thead>
<tr>
<td>Rank</td>
<td>Name</td>
<td>Price</td>
</tr>
</thead>
<tbody>
{this.state.data.map((n, i) => {
return (
<tr>
<td> <span onClick={() => this.handleClick(i)}> {n.starIcon ? <StarBorder/> : <Star /> } </span> </td>
<td>{n.name}</td>
<td>{n.current_price}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
}
export default Test;
Hope it helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With