1

I have an react application, where I'm rendering some pictures and gifs, that a user can attach to a post.

Right now I have an onClick handler on each image, so that either a modal pops op, wit some different options, or the picture gets deleted (if the user holds down the ctrl key):

showModalSpeceficHandler = (event, image) =>{
    let index = this.state.images.indexOf(image)
    if(event.ctrlKey){
     this.state.images.splice(index, 1);
 }else{
 this.setState(
     state => ({imageModalData: image}),
     () => this.showModalHandler()
 );
}

The problem is that if the first condition is met the view is not updated automatically. And i can't use and arrow function to re-render since I'm using the splice method on the image. Is there anyway to make the component re render, so that it updates the UI?

I'm not sure if I should wrap the code inside the if condition, inside a separate handler or I can use some Arrow Function syntax or a like?

EDIT:

I updated the method, so I set the state dynamically:

 if(event.ctrlKey){
      this.setState(
          state => ({images: this.state.images.splice(index, 1)})
      )

The issue now is that I want to return the entire array in not just the selected picture.

norbitrial
  • 14,716
  • 7
  • 32
  • 59
Kristoffer Tølbøll
  • 3,157
  • 5
  • 34
  • 69
  • 2
    Try using set state instead of directly trying to mutate state -> this.state.images.splice(index, 1); – Code Maniac Nov 30 '18 at 14:35
  • I'm voting to close this question as off-topic because this is basic React usage covered by the first page of the official tutorial and documentation. – Jared Smith Nov 30 '18 at 14:41

2 Answers2

3

The problem is you are not updating the state properly. If you want to make a change to the state, you MUST use setState, no matter what, otherwise React doesn't know that it has changed and will not update/render with the changes. See the React documentation for more details.

Since you need to remove an element from the array, you will have to make a temporary/intermediate copy to modify, then reassign it in the setState function:

let temp = this.state.images.slice(); //makes a shallow copy of the array
temp.splice(index, 1); //remove item
this.setState(prevState => ({ images: temp })); //update state
Herohtar
  • 5,347
  • 4
  • 31
  • 41
  • 2
    To put it slightly differently, `setState` is how you tell React that something changed. If you don't use it, it doesn't know. – Jared Smith Nov 30 '18 at 14:40
  • when you call slice the first time, you get a copy of the current array, and then set the state to that array, after removing the index? – Kristoffer Tølbøll Nov 30 '18 at 14:55
  • 1
    @baileyhaldwin [`slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) allows you to make a shallow copy of an array so that you're not modifying the state directly. [`splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) then removes the item at the selected index from the copy. Then the state is updated with the modified copy. – Herohtar Nov 30 '18 at 15:00
2

As it was said, you can't mutate the state. If you do so, the component will not be rerendered. What you can do in this case is simply use setState in both cases and replace splice method with filter.

inside of the setState

images: state.images.filter(img => img !== image)

Matus Dubrava
  • 13,637
  • 2
  • 38
  • 54