String prop passed to react child component from parent - unable to conver to Object with JSON.parse()

Question!

Problem Summary:

React component SLTree reads (ajax) a JSON, converts to string and passes it as property to two 'contained' components - Editor and TNode. Editor component (which encapsulates CodeMirror) works OK, but the TNode component event after JSON.parse() of the received property keeps interpreting the returned object as a string, instead of Object.

JSON file (validated):

"x":  {
            "id": 1,
            "content": "Hello, world!\n"
        },
"y":  {
            "id": 2,
            "content": "React is awesome.\n"
        },
"z":  {
            "id": 3,
            "content": "Robots are pretty cool.\n"
        },
"l":  {
            "id": 4,
            "content": "Monkeys.\nWho doesn't love monkeys?\n"
        }
}

React Components:

  • Parent: SLTree (reads above JSON using JQuery ajax)
  • Child: Editor - works correctly)
  • TNode - fails to 'Object'ify the passed string property.
    • JSON.parse(prop-passed-by-parent)
    • JSON.parse(JSON.stringify(prop-passed-by-parent)) - some answers on stackoverflow suggest using explicit stringify, before parse

Some reference indicated explicitly doing a stringify before parse. So I also tried:

let expectObj_gettingString = JSON.parse(JSON.stringify(this.props.node))

Code for parent component - SLTree:

import Editor from './Editor.jsx';
import TNode from './TNode.jsx';    
var $ = require('jquery');
const lstyle = {
  border: "solid navy 1px"
}
export default React.createClass({

  getInitialState: function() {
    return {
      displayText: ''
    }
  },
  componentDidMount: function() {
    this.serverRequest = $.ajax({
      url: "./sltree/sample.json",
      dataType: 'json',
      cache: false,
      success: function(data) {
        console.log(data);
        this.setState({displayText: JSON.stringify(data, null, ' ')});
      }.bind(this),
      error: function(xhr, status, err) {
        // console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  componentWillUnmount: function() {
    this.serverRequest.abort();
  },
  render() {
    return (
      <div className="row">
        <div style={lstyle} className="col-lg-6 col-md-6 col-sm-6 col-xs-6">
          <Editor displayText={this.state.displayText} />
        </div>
        <div style={lstyle} className="col-lg-6 col-md-6 col-sm-6 col-xs-6">
          <TNode node={this.state.displayText} />
        </div>
      </div>
    )
  }
});

Editor component works correctly.

TNode component below fails to convert this.props.node to a JSON object - and keeps interpreting it as a string - as evident from console logs below and display on the browser (not shown here)

import React from 'react';
import ReactDOM from 'react-dom';
var $ = require('jquery');

export default React.createClass({
  render() {
    let n = this.props.node;
    console.log("node type:("+ typeof n + ")")
    let s = "";
    for (var k in n) {
      s += k + " : " + n[k] + " : typeof n[k]("+typeof n[k]+")\n";
      console.log(s);
    }
    return (
      <div>{s}</div>
    );
  }
});

Here's the sample console log - note how 'node' is interpreted as string, instead of object. Note that index(key) is integer and value is character in the string.

    node type:(string)
bundle.js:70 document ready in sltree/main.js: dependencies loaded.
bundle.js:20470 Object {x: Object, y: Object, z: Object, l: Object}l: Objectcontent: "Monkeys.↵Who doesn't love monkeys?↵"id: 4__proto__: Objectx: Objectcontent: "Hello, world!↵"id: 1__proto__: Objecty: Objectz: Object__proto__: Object
bundle.js:41476 node type:(string)
bundle.js:41480 0 : { : typeof n[k](string)

bundle.js:41480 1 : 
 : typeof n[k](string)

bundle.js:41480 2 :   : typeof n[k](string)

bundle.js:41480 3 : " : typeof n[k](string)

bundle.js:41480 4 : x : typeof n[k](string)

bundle.js:41480 5 : " : typeof n[k](string)

bundle.js:41480 6 : : : typeof n[k](string)

bundle.js:41480 7 :   : typeof n[k](string)

bundle.js:41480 8 : { : typeof n[k](string)

bundle.js:41480 9 : 
 : typeof n[k](string)

bundle.js:41480 10 :   : typeof n[k](string)

bundle.js:41480 11 :   : typeof n[k](string)

bundle.js:41480 12 : " : typeof n[k](string)

bundle.js:41480 13 : i : typeof n[k](string)

bundle.js:41480 14 : d : typeof n[k](string)

bundle.js:41480 15 : " : typeof n[k](string)

bundle.js:41480 16 : : : typeof n[k](string)

bundle.js:41480 17 :   : typeof n[k](string)

bundle.js:41480 18 : 1 : typeof n[k](string)

bundle.js:41480 19 : , : typeof n[k](string)

bundle.js:41480 20 : 
 : typeof n[k](string)

bundle.js:41480 21 :   : typeof n[k](string)

bundle.js:41480 22 :   : typeof n[k](string)

bundle.js:41480 23 : " : typeof n[k](string)

bundle.js:41480 24 : c : typeof n[k](string)

bundle.js:41480 25 : o : typeof n[k](string)

bundle.js:41480 26 : n : typeof n[k](string)

bundle.js:41480 27 : t : typeof n[k](string)

bundle.js:41480 28 : e : typeof n[k](string)

bundle.js:41480 29 : n : typeof n[k](string)

bundle.js:41480 30 : t : typeof n[k](string)

bundle.js:41480 31 : " : typeof n[k](string)

bundle.js:41480 32 : : : typeof n[k](string)

bundle.js:41480 33 :   : typeof n[k](string)

bundle.js:41480 34 : " : typeof n[k](string)

bundle.js:41480 35 : H : typeof n[k](string)

bundle.js:41480 36 : e : typeof n[k](string)

bundle.js:41480 37 : l : typeof n[k](string)

bundle.js:41480 38 : l : typeof n[k](string)

bundle.js:41480 39 : o : typeof n[k](string)

bundle.js:41480 40 : , : typeof n[k](string)

bundle.js:41480 41 :   : typeof n[k](string)

bundle.js:41480 42 : w : typeof n[k](string)

bundle.js:41480 43 : o : typeof n[k](string)

bundle.js:41480 44 : r : typeof n[k](string)

bundle.js:41480 45 : l : typeof n[k](string)


Answers

I think the problem may come from this line:

this.setState({displayText: JSON.stringify(data, null, ' ')});

When your frontend receives the data from the AJAX call on this line, it has already been JSON.stringified. By stringifying it again, you are adding another pair of quotation marks, which means that when you parse it, it only removes that pair, but doesn't parse it back into an object.

Try: this.setState({displayText: data});

This will set displayText to be the stringified JSON. You will then need to parse it in the child component.

You could also do: this.setState({displayText: JSON.parse(data)});

In which case the data will be parsed and stored in state as an object, and should be accessible as it is to all child components.

By : otajor


This video can help you solving your question :)
By: admin