Home > Software engineering >  My setstate method is called multiple times which is causing a problem in deleting items in React Na
My setstate method is called multiple times which is causing a problem in deleting items in React Na

Time:11-23

I'm new to React Native and working on a small project. I'm calling a network call and rendering items in a FlatList. Im getting issue when deleting items because setRenderData method is called continously. How do i prevent this from happening? how do i call it only once? I have tried some solutions but i can't understand where the issue is. Please help me.

export default function TextExtractor() {
  const [pickerResponse, setPickerResponse] = useState(null);
  const [visible, setVisible] = useState(false);
  var [renderData, setRenderData] = useState([]);
const onRemove = id => e => {
   setRenderData(renderData.filter(renderData => renderData.Id !== id))
   };
   const Item = ({ title,id }) => (
     <View style={styles.item}>
       <Text style={styles.title}>{title}</Text>
    <TouchableOpacity  onPress={onRemove(id)}>
       <Image
style={{width:30,height:30}}
            source={require('../assets/delete.png')}
          />
          </TouchableOpacity>
     </View>
   );

  useEffect(() => {
   
    return () => {
      setRenderData({});
    };
}, []);

  const onImageLibraryPress = useCallback(() => {
  
    const options = {
      selectionLimit: 1,
      mediaType: 'photo',
      includeBase64: false,
    };
    ImagePicker.launchImageLibrary(options, setPickerResponse);
  }, []);

  const onCameraPress = useCallback(() => {
    const options = {
      saveToPhotos: true,
      mediaType: 'photo',
      includeBase64: false,
      maxWidth: 500,
      maxHeight: 500,
      quality: 0.5,
    };
    ImagePicker.launchCamera(options, setPickerResponse);
  }, []);

  const handleUploadPhoto = () => {
    setVisible(false);
  
     const data = new FormData();
   

      data.append("file_uploaded", {
         name: pickerResponse.assets[0].fileName,
         type: pickerResponse.assets[0].type,
         uri:
           Platform.OS === "android"
             ? pickerResponse.assets[0].uri
             : pickerResponse.assets[0].uri.replace("file://", "")
       }); 
 
       var url ='https://bacodetextextract.com/upload/image/';
   
       axios.post(url, data, {headers: {
         "Content-Type": "multipart/form-data",
         Accept: "application/json"
        
       }})
       .then((res) => {
    
        setRenderData(res.data);
     

         console.log(‘RESULT: ',renderData);

 
       })
       .catch((err) => {
         console.log('error', err);
       })
   };

  const uri = pickerResponse?.assets && pickerResponse.assets[0].uri;

  if(uri!==undefined){
 

  handleUploadPhoto();
  }

  const renderItem = ({ item }) => (
    <Item title={item.Text}
    id = {item.Id}
    />
  );
  return (
    <View style={styles.screen}>
 
      <ImagePickerAvatar uri={uri} onPress={() => setVisible(true)} />

      <FlatList style={styles.usernameText}
        data={renderData}
        renderItem={renderItem}
        keyExtractor={item => item.Id}
      />
     
      <ImagePickerModal
        isVisible={visible}
        onClose={() => setVisible(false)}
        onImageLibraryPress={onImageLibraryPress}
        onCameraPress={onCameraPress}
      />


    </View>
  );
}

});

CodePudding user response:

It's not a problem that setRenderData is called repeatedly, but there are two problems in your code:

  1. onPress={onRemove(id)} should be onPress={() => onRemove(id)}. You need to provide a function as the onPress property, not the result of calling a function.

  2. Whenever you're setting new state based on existing state, it's best practice (and often necessary practice) to use the callback version of the function so that you're operating on up-to-date state. You pass in a function that receives the up-to-date state:

    setRenderData(renderData => renderData.filter(
        renderData => renderData.Id !== id
    ));
    

Side note: Part of your code is expecting renderData to be an array, but another part of your code is doing setRenderData({}), which will make it a non-array object. It happens that part of the cleanup callback of a useEffect with no dependencies so that object isn't going to be used by the component (because that cleanup is only done when the component is unmounted), but it's still not best practice. (There's also no need to do that, all state is released when the component is unmounted.)

CodePudding user response:

T.J.Crowder solved your problem with the repeated re-rendering. The second problem is this part of your code:

const onRemove = id => e => {
   setRenderData(renderData.filter(renderData => renderData.Id !== id))
   };

I don't think id => e=> {} is a valid syntax, it should be like this:

const onRemove = (id) => {
   setRenderData(renderData.filter(renderData => renderData.Id !== id))
   };
  • Related