LoseYou21
LoseYou21

Reputation: 65

React change specific element in an array of objects

so i have an array of objects like so

enter image description here

Currently i'm looping through the array and displaying all the item.clock minutes. Now on click i want to change the display to item.activeTeamAbbr but just for that specific element, currently it is updating every element of the array. Just wondering what the best way to go about this would be, presumably to use a for loop? I'll add the code below, any help is much appreciated.

class Bets extends Component {
  constructor(props) {
    super(props);

    this.state = {
      items : [],
      showVid: false
    };
  }

  componentDidMount() {
    fetch('http://www.nfl.com/feeds-rs/bigPlayVideos/2018/REG/5.json')
      .then(response => response.json())
      .then(res => this.setState({items : res.bigPlays}))
   }


   showVideo(item){
    this.setState({showVid: true})
   }

   displayInfo(){
    let item = this.state.items.map((item, key) =>
    <li key={item.id}><button onClick={()=> this.showVideo(item)}> . 
    {item.clockMinutes}</button></li>
   );

   let displayInfo = this.state.items.map((item, key) =>
   <li key={item.id}>{item.activeTeamAbbr}</li>
  );

   if(this.state.showVid === false){
      return item
   }
      else return displayInfo
   }


  render() {
    return (
      <div>
        {this.displayInfo()}
      </div>
    );
  }
}

export default Bets;

Upvotes: 1

Views: 516

Answers (2)

fmoliveira
fmoliveira

Reputation: 376

A for loop would do, but a map may be cleaner. You need to keep track of what item you want to show, and inside the map, you will conditionally render it in one way or another.

Let's do a walkthrough so I can explain every detail.

In your showVideo(item) method, you need to keep track of what item you want to display. Start by storing its id in the state:

showVideo(item) {
  this.setState({ showVid: item.id });
}

Your displayInfo() method will return a list and for each item it will call another function that will decide what to render:

displayInfo() {
  return this.state.items.map(item => (
    <li key={item.id}>
      {displayItem(item)}
    </li>
  ))
}

The new displayItem(item) function will ask another function if the current item is selected, and conditionally render one thing or another:

const displayItem = item => {
  if (isSelected(item)) {
    return // render the activeTeamAbbr here
  }
  return // render the unselected state here, which is the button
}

The new isSelected(item) function will compare the item id against the id you stored in the state. It can be defined as follows:

const isSelected = item => this.state.showVid === item.id

If you want to allow multiple items to be switched, instead of a single one, the showVid state variable would be an object storing the states of each item:

constructor(props) {
  super(props);

  this.state = {
    items: [],
    showVid: {} // this should be an object to store multiple ids
  };
}

showVideo(item) {
  this.setState({ showVid: { ...this.state.showVid, [item.id]: true}})
}

And simply modify the isSelected function defined previously in order to support the new type of the showVid variable:

const isSelected = item => this.state.showVid[item.id]

Upvotes: 1

Tholle
Tholle

Reputation: 112777

Instead of having a single showVid state variable for all your items, you could have one on every element in the array and toggle that when the button is clicked.

Example

class Bets extends React.Component {
  state = {
    items: [],
    showVid: false
  };

  componentDidMount() {
    fetch("https://www.nfl.com/feeds-rs/bigPlayVideos/2018/REG/5.json")
      .then(response => response.json())
      .then(res => this.setState({ items: res.bigPlays }));
  }

  showVideo = (index) => {
    this.setState(prevState => {
      const items = [...prevState.items];
      items[index] = {
        ...items[index],
        showVid: !items[index].showVid
      };
      return { items };
    });
  }

  render() {
    return (
      <div>
        {this.state.items.map((item, index) => (
          <li key={item.id}>
            {item.showVid ? (
              item.activeTeamAbbr
            ) : (
              <button onClick={() => this.showVideo(index)}>
                {item.clockMinutes}
              </button>
            )}
          </li>
        ))}
      </div>
    );
  }
}

ReactDOM.render(<Bets />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

Upvotes: 1

Related Questions