TypeError: Invalid attempt to spread non-iterable instance

This is because it is a runtime error, not a "compile time" error.

Is there a line number associated with the error? Based on the question being about the spread operator I'll assume it's this line: newArticlesData=[...prevData,...response.data]. I assume your prevData is iterable, but is your response data? Try newArticlesData=[...prevData, response.data]?

Here's an example of invalid spread operator use:

function trySpread(object) {
  let array;
  try {
    array = [...object];
    console.log('No error', array);
  } catch(error) {
    console.log('error', error);
  }
}

// error
trySpread({});
trySpread({foo: 'bar'});
trySpread(4);

// no error
trySpread([]);
trySpread(['foobar']);
trySpread('foobar');

I was getting this crash in release android build only. release ios build and android debug build working perfectly.

After spending a few hours found solutions from the internet.

edit your .babelrc and add following into your plugins

[
      "@babel/plugin-transform-spread",
      {
        "loose": true
      }
    ]

so Here is my .babelrc file

{
  "presets": [
    "module:metro-react-native-babel-preset"
  ],
  "plugins": [
    "syntax-trailing-function-commas",
    "@babel/plugin-transform-flow-strip-types",
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-transform-regenerator",
    "@babel/plugin-transform-async-to-generator",
    "@babel/plugin-transform-runtime",
    [
      "@babel/plugin-transform-spread",
      {
        "loose": true
      }
    ]
  ],
  "sourceMaps": true
}

I hope this answer helps someone and save few hours :)


I removed prevData and replaced it with this.state.articlesData. I also change the logic so at the begining when articlesData is empty, it doesn't merge two objects, instead just uses the response.data.

if(propSearch=="" || propSearch==null && this.state.currentPage!=1 && refresh!=true){
    newData=[...this.state.articlesData,...response.data]
}
else{
    newData=response.data
}

this.state.currentPage!=1 is pretty much the same as oldData != empty

It workes now.


this is because you play around with objects but you trying to copy objects in the array

convert this line

newArticlesData = [...prevData, ...response.data];

to

 newArticlesData = {...prevData, ...response.data};

Your problem solved my code for this is

 fetch(url, {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        'x-sh-auth': userToken || userStoredToken,
      },
    })
      .then(response => response.text())
      .then(async responseText => {
        let responseData = JSON.parse(responseText);
        console.log('responseData HomeWhatsNewUser', responseData);
        if (responseData.code == 200) {
          setpageNumberwhatsnewap(pageNumberwhatsnewapi + 1);
          setiSloding(false);
          setWhatsNewAPiUser({...WhatsNewAPiUser, ...responseData});
          // setWhatsNewAPiUser(responseData);
          // setLoadMoreNewUserApiLink(responseData.load_more_url);
        } else {
          if (responseData.message === 'Your are un authorize') {
            await AsyncStorage.removeItem('@userData');
            await AsyncStorage.removeItem('@userToken');
            props.navigation.navigate('HomeScreen');
          }
          Toast.show({
            text1: responseData.message,
          });
          setiSloding(false);
        }
      })
      .catch(error => {
        setiSloding(false);
        console.log(error, 'error from APi');
      });
  };