react-native-snap-carousel icon indicating copy to clipboard operation
react-native-snap-carousel copied to clipboard

RenderItem doesn't refresh when state change

Open MelanieCroce opened this issue 4 years ago • 10 comments

Is this a bug report, a feature request, or a question?

A bug report

Have you followed the required steps before opening a bug report?

Have you made sure that it wasn't a React Native bug?

it's not a react native bug.

Is the bug specific to iOS or Android? Or can it be reproduced on both platforms?

I just test to Android.

Is the bug reproductible in a production environment (not a debug one)?

I don't use it to prod. I check in my phone with react-native run-android.

Environment

Environment: React: 16.8.6 React native: 0.60.5 react-native-snap-carousel: 3.8.2

Target Platform: Android (6.0)

Expected Behavior

I have 3 items. Each item is a button that opens the camera. Once we take the picture, it should show the picture instead of the button for each item.

Actual Behavior

When I take the photo, it updates the state but it does not display the photo.

Reproducible Demo

<Carousel
                        ref={(c) => { this._carousel = c; }}
                        data={[
                            {key: 0, urlImage: this.state.urlImage1,},
                            {key: 1, urlImage: this.state.urlImage2,},
                            {key: 2, urlImage: this.state.urlImage3,},
                        ]}
                        extraData={this.state}
                        renderItem={this._renderItem}
                        sliderWidth={screen.width}
                        sliderHeight={300}
                        itemWidth={300}
                        itemHeight={300}
                        containerCustomStyle={{
                            flexGrow: 0,
                        }}
                    />
_renderItem ({item, index}) {
       return (
           <View style={{ width: 300, height: 300, position: "relative", marginTop: 20 }}> 
               { item.urlImage == "data:image/jpeg;base64" ? 
                   <TouchableOpacity 
                       onPress={(e) => this.takePhoto(e, item.urlImage)}  
                       style={{ backgroundColor: 'transparent', borderColor: 'white', borderWidth: 1 ,width: 300, height: 300,  zIndex: 9999, elevation: 9999, position: "absolute", top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'center', alignItems: 'center' }}
                   >
                       <View>
                           <Icon 
                               type="MaterialIcons"
                               name="add-a-photo"
                               size={95}
                               color={"white"}
                           />
                       </View>
                   </TouchableOpacity>
                   : <View></View> 
               }
               <Image
                   source={{ uri : item.urlImage }}
                   style={{ width: 300, height: 300, backgroundColor: "#046381" }}
               />
           </View>
       );
   }
takePhoto(e, item) {
        ImagePicker.launchCamera(options, (response) => {
            if (response.error) {
                console.log('ImagePicker Error: ', response.error);
            } 
            else {
                const source = { uri: 'data:image/jpeg;base64,' + response.data };
                this.setState({
                    [item]: source.uri,
                    refresh: !this.state.refresh
                }, () => { console.log(this.state.refresh) });
            }
        })
    }

MelanieCroce avatar Oct 25 '19 09:10 MelanieCroce

I have an issue with updating the state in component.

In my case, I am changing the width of the sliderWidth and itemWidth when the layout of the container view changes.

In a first moment the carousel re-render it self, but it doesn´t always apply.

josuevalrob avatar Nov 04 '19 13:11 josuevalrob

Hi. I don't know if you've solved the problem, but I had the same problem today. If you do as in the example below, the high probability of the problem will be solved. I hope it helps.

state = { refresh: false, };

<Carousel ref={(c) => { this._carousel = c; }} data={[ {key: 0, urlImage: this.state.urlImage1,}, {key: 1, urlImage: this.state.urlImage2,}, {key: 2, urlImage: this.state.urlImage3,}, ]} extraData={this.state.refresh} renderItem={this._renderItem} sliderWidth={screen.width} sliderHeight={300} itemWidth={300} itemHeight={300} containerCustomStyle={{ flexGrow: 0, }} />

takePhoto(e, item) { ImagePicker.launchCamera(options, (response) => { if (response.error) { console.log('ImagePicker Error: ', response.error); } else { const source = { uri: 'data:image/jpeg;base64,' + response.data }; this.setState({ [item]: source.uri, refresh: !this.state.refresh }, () => { console.log(this.state.refresh) }); this.setState({ refresh: !refresh}); } }) }

kasim444 avatar Dec 02 '19 08:12 kasim444

@kasim444 extraData props is available?

riseworld27 avatar Apr 24 '20 02:04 riseworld27

up! currently having problems refreshing the component as well! Any clue on how to force refresh?

ruggero-balteri avatar May 04 '20 13:05 ruggero-balteri

Any news about this?

LeandroSuarez avatar Jun 07 '20 17:06 LeandroSuarez

Also having this issue. I have the carousel sitting over a map screen and when users zoom out or changes the map view, the data set is then altered. This causes an issue with the scroll behavior of the carousel and prevents it from scrolling.

jbromberg avatar Jun 09 '20 21:06 jbromberg

Still not working ...

nickjuntilla avatar Mar 03 '21 03:03 nickjuntilla

I solved this by doing a setTimeOut and forcing a re-render of the whole page by toggling my isLoading state element. It's not the best solution, but it works:

` componentDidUpdate = () => {

if (
  JSON.stringify(this.props.unsavedItem.images) !==
    JSON.stringify(this.state.carouselData)
) {

  this.setState({
    carouselData: this.props.unsavedItem.images,
    isLoading: true,
  });

  // Weird hack to fix the missing image because
  // Carousel doesn't refresh when changing images
  setTimeout(() => {
    this.setState({ isLoading: false });
  }, 150);
}

};`

Of course you need to have your main content toggled by your isLoading.

nickjuntilla avatar Mar 03 '21 04:03 nickjuntilla

Sorry, please allow me to advertise for my open source library! ~ I think this library react-native-reanimated-carousel will solve your problem. It is a high performance and very simple component, complete with React-Native reanimated 2

dohooo avatar Oct 08 '21 05:10 dohooo

You can try use triggerRenderingHack().

useEffect( () => {
	carouselRef.current.triggerRenderingHack();
}, [ items ] );

...

<Carousel
	ref={carouselRef}
	data={items}
	renderItem={renderItem}
	onSnapToItem={_setCarouselIndex}
	sliderWidth={screenWidth}
	itemWidth={screenWidth}
/>

denisbevilacqua avatar Feb 09 '22 17:02 denisbevilacqua