15

We're building a RN app (RN0.37), and we're running into an issue where when the app is run, we get a "TypeError: JSON.stringify cannot serialize cyclic structures".

Nothing of relevance has changed on the API responses, and the issues went away recently, but reappeared upon a wipe/rebuild (triggered by unrelated issues).

My suspicions are around a couple of packages being used: “react-native-router-flux” and "react-native-permissions”, but I haven't been able to find anything of relevance in the app.

Currently my suspicions around "react-native-router-flux" are mainly based around this article: https://github.com/aksonov/react-native-router-flux/issues/363

And my suspicions around "react-native-permissions" is mostly founded on the fact that the timing of the inclusion of this package on this project is suspicious, and seems to coincide with the surfacing of this error - although I can't prove that with absolute certainty.

The only additional clue I have, is that the JSON.stringify error always seems to be preceded by a list of warnings. They all read "This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See https://facebook.github.io/react/docs/events.html#event-pooling for more information." The list of goes as follows (always in the same order): nativeEvent, type, target, currentTarget, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, isTrusted and touchHistory.

The following is my package.json:

"dependencies": {
  "blueimp-md5": "2.5.0",
  "moment": "2.16.0",
  "phone-formatter": "0.0.2",
  "react": "15.3.2",
  "react-native": "0.37.0",
  "react-native-asset-library-to-base64": "1.0.1",
  "react-native-aws3": "0.0.3",
  "react-native-button": "1.7.1",
  "react-native-cached-image": "1.2.2",
  "react-native-camera-kit": "4.0.1",
  "react-native-camera-roll-picker": "1.1.9",
  "react-native-contacts": "0.5.2",
  "react-native-fbsdk": "0.4.0",
  "react-native-fetch-blob": "0.10.0",
  "react-native-fs": "2.0.1-rc.2",
  "react-native-geocoder": "0.4.5",
  "react-native-image-crop-picker": "0.10.5",
  "react-native-image-resizer": "0.0.12",
  "react-native-nav": "1.1.4",
  "react-native-permissions": "0.2.5",
  "react-native-photo-view": "1.2.0",
  "react-native-router-flux": "3.37.0",
  "react-native-stripe": "1.2.1",
  "react-native-swipe-list-view": "0.3.1",
  "react-redux": "4.4.6",
  "redux": "3.6.0",
  "redux-storage": "4.1.1",
  "redux-storage-engine-reactnativeasyncstorage": "1.0.2",
  "underscore": "1.8.3"
}
Sid Mhatre
  • 3,272
  • 1
  • 19
  • 38
Vicente Opaso
  • 151
  • 1
  • 1
  • 5
  • Are you perhaps logging a cyclic object out to console, and serialising it first? – G0dsquad Feb 16 '17 at 09:52
  • We discovered that the issues has been there all along, and the reason for its intermittence had to do with the use of Javascript Debugging being enabled on the emulator. Still not sure what the issue is. – Vicente Opaso Feb 17 '17 at 15:41

4 Answers4

12

Passing this getCircularReplacer function as a second parameter into JSON.stringify() will fix this error:

const getCircularReplacer = () => {
    const seen = new WeakSet();
    return (key, value) => {
    if (typeof value === "object" && value !== null) {
        if (seen.has(value)) {
            return;
        }
        seen.add(value);
    }
    return value;
    };
};

Then you can use it as follows:

JSON.stringify(circularReference, getCircularReplacer());
// {"otherData":123}
Bill Zelenko
  • 2,606
  • 1
  • 17
  • 26
  • Why would you use a WeakSet here? Wont all the allocated memory for the set be cleared when the stringification is done? – Alexandre Dias Sep 01 '22 at 16:21
  • JSON.stringify needs to know when to stop the strange loop. The allocated memory is not cleared until a duplicate is found. – Bill Zelenko Oct 08 '22 at 05:05
5

JSON.stringify can not handle JSON objects that have a reference to itself or portions of itself.

Link

I've made a simple library for the lazy that overrides the JSON.stringify() to allow it to handle circular references without producing an exception. It keeps you from changing anything in 3rd party libraries concerning this limitation. Install this at the bootstrap of your code.

Link 2

always-a-learner
  • 3,671
  • 10
  • 41
  • 81
kbaylosis
  • 308
  • 2
  • 9
4

you're writing for REACT NATIVE but it seems you have used onChange on textInput instead of onChangeText which is a right method for React Native when you're interested with updated value of the text input,

ndotie
  • 1,830
  • 17
  • 18
  • onChange when used on REACT NATIVE will give back ```{ nativeEvent: { eventCount, target, text} }``` thats why JSON.stringify() is complaining its cyclic – ndotie Jun 28 '20 at 14:16
  • 2
    Welcome mate, lets hack this :) – ndotie Mar 07 '22 at 12:53
0

After spending half a day, I found this fantastic way, especially for React Naive, first of all, install json-stringify-safe, if you're working by using Typescript, install it too @types/json-stringify-safe.

Then I prepared these two utils functions:

import serialize from 'json-stringify-safe';

const stringify = (any: any): string => serialize(any);

const parsify = (serializedString: string): any => eval(`(${serializedString})`);
AmerllicA
  • 29,059
  • 15
  • 130
  • 154