0

I have

<ScrollView horizontal={true} >
  {this.state.images.map((uri,i) => 
  <Thumb key={i} number={i} uri={uri} onDelete ={this.deleteImage.bind(this)} /> )}
</ScrollView>

Here each Thumb class has Image. Whenever I click on the image it is required to be deleted from the ScrollView.

My Thumb component looks like this

 class Thumb extends React.Component {
constructor(props){
  super(props);

  this.state = {
    show : false
  }
}


  shouldComponentUpdate(nextProps, nextState) {
    console.log(nextProps,'nextprops')
    return false;
  }
  render() {
    return (
      <View style={[styles.button ]}>


            <View style={[{position:'relative'},styles.img]} >
              <View style={{position:'absolute'}}>
                <Image style={styles.img} source={{uri:this.props.uri.path}}/>
              </View>

              <View style={[styles.img , {position:'absolute',alignItems:'center',justifyContent:'center',opacity:1}]}>

              <TouchableHighlight onPress = {() => {this.props.onDelete(this.props))}}>
                <Icon name="close" size = {30} color="white"/>
                 </TouchableHighlight>
              </View>
            </View>

      </View>
    );
  }
}

and i'm trying to delete

deleteImage(deleteProp){
//  console.log(_scrollView)
//  _scrollView.props.children.splice(deleteProp.number,1)
//  console.log(_scrollView)
  console.log(deleteProp,'prop from delete method');
   console.log(this.state.images ,'before')
 let images = this.state.images;
 console.log(images.splice(deleteProp.number ,1),'splice data');
  this.setState({images : images});
 console.log(this.state.images,'after')
  if(this.state.images.length == 0 ){
    this.setState({loading:false})
  }
}

How should I achieve this?

I tried deleting the corresponding state wise Image object but its always deletes the last image of the ScrollView(or last Thumb component).

I'm new to react-native and Android I don't know this is possible with ScrollView. Please suggest me the correct method.

BradByte
  • 11,015
  • 2
  • 37
  • 41
santhosh
  • 1,919
  • 3
  • 21
  • 33
  • Can you post the code to delete the entry from state.images? Normally you want to pass the index/id of the item you want to delete, like ```this.deleteImage.bind(this, i)```, so that you know which one to delete. – fabio.sussetto Nov 17 '16 at 11:00
  • @fabio.sussetto i'm passing the index to delete the image – santhosh Nov 17 '16 at 11:47
  • @fabio.sussetto let images = this.state.images; images.splice(deleteProp.number ,1); this.setState({images : images}); – santhosh Nov 17 '16 at 11:49
  • A few things: 1) ```splice``` mutates the content of this.state.images in place. In React you should never mutate the state directly, use Array#slice instead. 2) how are you updating deleteProp? please post the full component class if you can so we can see what's going on. – fabio.sussetto Nov 17 '16 at 12:12
  • @fabio.sussetto i have updated the code... – santhosh Nov 17 '16 at 13:03
  • @fabio.sussetto were you able to find mistakes..sorry to bother you...i was in need of this to be working...in my project – santhosh Nov 19 '16 at 12:27

2 Answers2

2

This is a pretty common issue with confusing the role keys play in Components. We think of keys just as a unique identifier for the dynamically generated components. But it also serves as a means for React to know which components need to be redrawn.

As such, I would advise changing your key to be something unique to the image itself, not the position.

<Thumb key={uri.path} number={i} uri={uri} onDelete={this.deleteImage.bind(this)} />

Here's the official docs on keys.

The key only has to be unique among its siblings, not globally unique. As a last resort, you can pass item's index in the array as a key. This can work well if the items are never reordered, but reorders will be slow. (emphasis mine).

This is another good article about why keys are important.

Also, when you have arrays that are generating components, I like to "preload" the functions to not need indexes, ids, etc, passed up to it.

// original component
<Thumb key={i} number={i} uri={uri} onDelete={this.deleteImage.bind(this)} />
// updated function by adding index to bind params and unique key
<Thumb key={uri.path} number={i} uri={uri} onDelete={this.deleteImage.bind(this,i)} />

That way, when you want to delete you can simply call this.props.onDelete(). Just a preference but I think it's cleaner.

BradByte
  • 11,015
  • 2
  • 37
  • 41
0

Thumb:

class Thumb extends React.Component {
    constructor(props){
        super(props);

        this.state = {
            show : false
        }
    }

    shouldComponentUpdate(nextProps, nextState) {
        console.log(nextProps,'nextprops')
        return false;
    }

    render() {
        return (
            <View style={[styles.button ]}>
                <View style={[{position:'relative'},styles.img]} >
                    <View style={{position:'absolute'}}>
                        <Image style={styles.img} source={{uri:this.props.uri.path}}/>
                    </View>
                    <View style={[styles.img , {position:'absolute',alignItems:'center',justifyContent:'center',opacity:1}]}>
                        <TouchableHighlight onPress = {this.props.onDelete}>
                            <Icon name="close" size = {30} color="white"/>
                        </TouchableHighlight>
                    </View>
                </View>
            </View>
        );
    }
}

ScrollView

<ScrollView horizontal={true} >
    {this.state.images.map((uri,index) => 
    <Thumb key={index} uri={uri} onDelete={this.deleteImage.bind(this, index)}/> )}
</ScrollView>

deleteImage()

deleteImage(index) {
    const images = this.state.images;
    const newImages = [...images.slice(0, index), ...images.slice(index + 1, images.length)];
    let newState = { images: newImages };

    if(images.length === 0){
        newState = { ...newState, loading: false };
    }

    this.setState(newState);
}
yadhu
  • 15,423
  • 7
  • 32
  • 49