question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Button on card triggers setState, but does not re-render

See original GitHub issue

Hello everyone,

I have used this plugin for my project and really like it. Thank you for your work. I’m trying to implement couple transparent buttons on top of the card to go back and forth in an image array for each card (much like Instagram does it). The button does get called. However, the setState in the call does not make the UI to re-render. I have looked up what might cause it and used the solutions from other answers to trigger re-render and they work fine, but within the Card, it does not work for some reasons. Here are my codes:

return (
      <View style={{ flex: 1 , backgroundColor: '#efede6', flexDirection: 'column'}}>
        <View style={{ flex: 1 ,backgroundColor: 'blue'}}>

        </View>
        <View style={{ flex: 8 , backgroundColor: 'red'}}>
          <Swiper
              ref="deck"
              cards={this.state.restaurants}
              renderCard={(card) => {
                return(
                  <ImageBackground
                    style = {styles.card}
                    source = {{uri:card.photos[this.state.currentImageIndex]}}
                    borderRadius = {20}
                  >
                  {this.renderImageIndexes()};
                  <View
                    style = {styles.imageControllerButtonContainer}
                  >
                    <TouchableOpacity
                      style = {styles.imageControllerButton}
                      onPressOut = {()=>this.previousImage()}/>
                    <TouchableOpacity
                      style = {styles.imageControllerButton}
                      onPressOut = {()=>this.nextImage()}
                      hitSlop={{ top: 12, left: 36, bottom: 0, right: 0 }}/>
                  </View>
                  </ImageBackground>
                )
              }}
              onSwipedLeft={(cardIndex) => {
                this.previousRestaurant(cardIndex);
              }}
              onSwipedRight={(cardIndex) => {
                this.nextRestaurant(cardIndex);
              }}
              onSwipedAll={() => {console.log('onSwipedAll')}}
              cardIndex={0}
              backgroundColor={'#efede6'}
              showSecondCard = {true}
              stackSize= {this.state.restaurants.length}
              disableLeftSwipe = {this.state.firstRestaurant}
              goBackToPreviousCardOnSwipeLeft = {true}>

            </Swiper>
        </View>

      </View>
);

And here is the call to setState:

nextImage(){
    console.log("Get called!!!");
    if(this.state.currentImageIndex < 10){
      this.setState({
        currentImageIndex: this.state.currentImageIndex + 1,
      });
      console.log(this.state.currentImageIndex)
    }
  }

  previousImage(){
    if(this.state.currentImageIndex > 0){
      this.setState((state, props) => ({
        currentImageIndex: this.state.currentImageIndex - 1,
      }));
    }
  }

Appreciate any help

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
webraptorcommented, Nov 9, 2018

@baophamtd that wouldn’t work and it looks really hard to maintain.

  1. your renderCard method doesn’t use the cardIndex, which the swiper passes back as parameter. renderCard(card,cardIndex)
  2. your renderCard method is anonymous. You could move it a separate method
  3. when said function gets called, you’d setState({cardIndex}) so that your parent’s component cardIndex coincides with whatever’s on the swiper.
  4. within the swiper properties you set, replace cardIndex={0} with cardIndex={this.state. cardIndex={0}}
  5. When constructing the restaurants objects that get pushed into the this.state.restaurants array make sure you initialise a currentImageIndex with 0.
  6. Your source = {{uri:card.photos[this.state.currentImageIndex]}} would become source = {{uri:card.photos[card.currentImageIndex]}}
  7. Next/Previous image is as below, or similar:
nextImage(){
  const { restaurants, cardIndex } = this.state;
  this.setState({
    restaurants: [
      ...restaurants.slice(0, cardIndex), // if not familiar with this look for spread operator
      { 
        ...restaurants[cardIndex], 
        currentImageIndex: restaurants[cardIndex].currentImageIndex+1 
      }, 
      ...restaurants.slice(cardIndex+1, restaurants.length)
    ]
  });
}
  1. Of course, when you increment decrement stuff, you need to check that you won’t go out of bounds.
0reactions
codingdeepcommented, Dec 11, 2020

Really life saviour solution

Read more comments on GitHub >

github_iconTop Results From Across the Web

React: re render componet after button click - Stack Overflow
A simple way to re-render would be to change the state variable on the submission of the Axios request causing the component to...
Read more >
React doesn't always trigger a re-render on setState
For new React developers, it is common to think that setState will trigger a re-render. But this is not always the case. If...
Read more >
How to stop re-rendering lists in React? - Alex Sidorenko
Components always re-render. First, let's simplify our example by removing all props from the Item . We will still update the parent state...
Read more >
setstate not rerendering | The AI Search Engine You Control
The problem lies in your shouldComponentUpdate . Right now, it only returns true when the props of the new clientID is different than...
Read more >
Reconciliation - React
Just to be clear, rerender in this context means calling render for all components, it doesn't mean React will unmount and remount them....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found