在ReactJS应用程序中将字符串转换为JSON对象时出错

时间:2017-09-08 10:58:42

标签: javascript json reactjs parsing jsx

作为我不断努力学习ReactJS的一部分,我正在开发一个简单的页面,它将呈现如下趋势列表:

enter image description here

单击“获取趋势”按钮后,将通过websockets从后端服务器检索趋势列表并显示。它按预期工作。以下是相应的源代码:

import React, { Component } from 'react';
import './App.css';

class TrendRow extends Component {
  render() {
    return (
      <tr>
        <td>{this.props.onerow}</td>
      </tr>
    );
  }
}

class TrendTable extends Component {
  render() {
    var rows = [];
    for (var i=1; i<3; i++) {
      rows.push(<TrendRow key={i} onerow={this.props.trends[i]}/>);
    }
    return (
      <table>
        <thead>
          <tr>
            <th>List of Trends</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class App extends Component {
  constructor() {
    super();

    this.state = {
      ws: new WebSocket('ws://localhost:8025/websockets/TwitterWSService'),
      getTrendsqueryString: 'GETTRENDS',
      listoftrends: ['{"trend":"#Default","id":"0"}']
    };

    this.handleOnClick = this.handleOnClick.bind(this);
  }

  handleOnClick = (event) => {
    this.state.ws.send(this.state.getTrendsqueryString);
    this.state.ws.onmessage = (event) => {
      this.setState(prevState => ({listoftrends: prevState.listoftrends.concat(event.data)}));
    }
  }

  render() {
    return (
      <div>
          <button onClick={this.handleOnClick}>Get Trends</button>
          <TrendTable trends={this.state.listoftrends} />
      </div>
    );
  }
}

export default App;

现在,当我尝试使用“JSON.parse”将显示的JSON字符串转换为JSON对象时,我会根据解析它的位置得到不同类型的错误。

如果我解析如下,

class TrendRow extends Component {
  render() {
    var jsonobject = JSON.parse(this.props.onerow);
    return (
      <tr>
        <td>{jsonobject}</td>
      </tr>
    );
  }
}

我收到以下错误:

  

“SyntaxError:位于0的JSON中的意外标记u

     

...

     

var jsonobject = JSON.parse(this.props.onerow);

     

...“

快速谷歌搜索错误消息返回了以下讨论,但不清楚如何将解决方案应用于我的用例:

uncaught syntaxerror unexpected token U JSON

我理解错误是由于值'this.props.onerow'在初始渲染期间未定义而JSON.parse()试图解析此对象。即使使用默认字符串初始化“listoftrends”对象也无法解决错误。

如果另一方面我JSON.parse()如下所示,

  handleOnClick = (event) => {
    this.state.ws.send(this.state.getTrendsqueryString);
    this.state.ws.onmessage = (event) => {
      var jsonobject = JSON.parse(event.data);
      this.setState(prevState => ({listoftrends: prevState.listoftrends.concat(jsonobject)}));
    }
  }

我收到错误消息:

  

对象作为React孩子无效......

谷歌搜索让我陷入另一个兔子洞!有人可以为我提供任何其他解决方案吗?

5 个答案:

答案 0 :(得分:3)

查看您的代码(以及您刚学习的笔记),让我添加一些评论,说明如何改进它。

  1. 使用带有类属性的箭头函数可确保始终使用组件作为this的值调用方法,这意味着此处的手动绑定是多余的。所以你可以摆脱下面这一行。

    this.handleOnClick = this.handleOnClick.bind(this);

  2. 还要摆脱for中的丑陋TrendTable循环,并将其替换为You can read more函数。

    class TrendTable extends Component { render() { return ( <table> <tbody>{this.props.trends.map(trend => <TrendRow key={i} onerow={trend}/>)} </tbody> </table> ); } }

    this如果您要避免定期for循环,那么您有什么替代方案。

  3. 为了预先填充trends数组,更好的方法是使用componentDidMount反应生命周期方法。要深入了解stage-2 preset文章。

    我认为最好创建更新按钮(而不是获取趋势),如果需要,应该使用后端方面的新部分完全重写您的趋势列表(但确定这一点取决于您)

  4. 现在你不必在组件中使用构造函数方法,如果你只需要初始化默认状态,那么你可以使用 state = {....};只是在组件内部没有使用构造函数。但请确保您使用的是{{3}}。

  5. 因此,考虑到上述评论,这里是App组件:

    class App extends Component {
    
      state = {
          ws: new WebSocket('ws://localhost:8025/websockets/TwitterWSService'),
          getTrendsqueryString: 'GETTRENDS',
          listoftrends: [] // you can add default trend record if you need it
        };
      };
    
      componentDidMount() {
        this.fetchTrends();
      }
    
      fetchTrends = (completeUpdate = false) => { 
        this.state.ws.send(this.state.getTrendsqueryString);
        this.state.ws.onmessage = (event) => {
          this.setState(prevState => (
            { listoftrends: !completeUpdate ? prevState.listoftrends.concat(event.data) : event.data }
          ));
        }    
      };
    
      updateTrends = () => {
        this.fetchTrends(true); //in that case you'd like to completely update the list
      }
    
    }
      render() {
        return (
          <div>
            <button onClick={this.updateTrends}>Update trends</button>
            <TrendTable trends={this.state.listoftrends} />
          </div>
        );
      }
    }
    
    1. 关于你的问题本身。正如许多其他人已经提到的那样,是的,它不可能在JSX中使用对象,所以你必须先将它转换(例如转换为数组)。
    2. E.g。

      var array = Object.values(jsonobject).map(value => ...);
      
      // and then in JSX
      <div>{array}</div>
      

      希望这一切都有意义。

答案 1 :(得分:1)

%% In file 'run_fMRI_experiment.m' % Main experiment function function fMRIData = run_fMRI_experiment global fMRIData; F = figure; text(-1,0,{'Glorious Experiment, she is now runnink, yes?', 'Please to be pressink "5", I will collectink data.', '', 'Please to be pressink key of escapeness when finishedski, da?'}, 'fontsize', 14); axis off; axis ([-1, 1, -1, 1]); set (F, 'keypressfcn', @detectFirstKeyPress); waitfor(F); end % subfunctions (i.e. in same file) acting as callback functions function detectFirstKeyPress(CallerHandle, KeyPressEvent) if strcmp(KeyPressEvent.Key, '5') set (CallerHandle, 'keypressfcn', {@detectKeyPresses, tic()}); fprintf ('Experiment started at %s\n', datestr(now())); end end function detectKeyPresses (CallerHandle, KeyPressEvent, StartTime) if strcmp (KeyPressEvent.Key, '5'); global fMRIData; fMRIData(end+1) = toc(StartTime);; fprintf('"5" pressed at %d seconds.\n', fMRIData(end)); return elseif strcmp (KeyPressEvent.Key, 'escape'); disp ('Escape Pressed. Ending Experiment'); close (CallerHandle); end end 是一个对象。

React不知道如何呈现它。

您可以将其转换为数组,然后将其渲染。

jsonobject

JSX:

var jsonArray = Object.keys(jsonobject).map(function(k) { return jsonobject[k]; });

答案 2 :(得分:1)

使第一个方法工作的简单解决方案是在第一次渲染期间不尝试解析JSON来绕过错误:

var jsonobject = this.props.onerow ? JSON.parse(this.props.onerow) : {};

正如其他人所说,你无法直接渲染对象。出于测试目的,请将<td>{jsonobject}</td>替换为<td>{jsonobject.id}</td>

答案 3 :(得分:0)

如果您记录JSON解析的初始行和结果,例如

console.log(this.props.onerow);
console.log(JSON.parse(this.props.onerow));

控制台的输出是什么?您的第一个错误可能是因为后端的“JSON”响应没有正确构造,或者因为最初如果值类似于空字符串,那么您不能在其上使用JSON.parse,因为它会导致错误。

第二个错误Objects are not valid as a React child是当您尝试在JSX元素中渲染对象时发生的情况,例如:

render(){
    let someObj = {potato:1, hello:'hi there'};
    return(<div>Here's the object: {someObj}</div>); <-- ERROR! can't put an object here
}

所以我猜你在某个时候试图在JSX元素中渲染JSON对象。

答案 4 :(得分:0)

在合并用户提供的建议后,我提供了更新的代码。这可能不完美但完成了我想要的。

import React, { Component } from 'react';
import './App.css';

class TrendRow extends Component {
  render() {
    var jsonArray = Object.keys(this.props.onerow).map((k) => {
                                                  return this.props.onerow[k];
                                                  });
    return (
      <tr>
        <td>{jsonArray[0]}</td>
      </tr>
    );
  }
}

class TrendTable extends Component {
  render() {
    var rows = this.props.trends.map((trend, index) => {
          return (index<2) ? <TrendRow key={index} onerow={trend} /> : [];
        }
      );

    return (
      <table>
        <thead>
          <tr>
            <th>List of Trends</th>
          </tr>
        </thead>
        <tbody>{rows}</tbody>
      </table>
    );
  }
}

class App extends Component {
  constructor() {
    super();

    this.state = {
      ws: {},
      getTrendsqueryString: 'GET',
      listoftrends: []
    };
  }

  componentDidMount = () => {
    this.setState({ws: new WebSocket('ws://localhost:8025/websockets/TwitterWSService')});
  }

  handleOnClick = (event) => {
    this.state.ws.send(this.state.getTrendsqueryString);
    this.state.ws.onmessage = (event) => {
      var jsonobject = JSON.parse(event.data);
      this.setState(prevState => ({listoftrends: prevState.listoftrends.concat(jsonobject)}));
    }
    this.state.ws.onclose = (event) => {
      this.setState({ws: new WebSocket('ws://localhost:8025/websockets/TwitterWSService')});
    }
  }

  render() {
    return (
      <div>
          <button onClick={this.handleOnClick}>Get Trends</button>
        <TrendTable trends={this.state.listoftrends} />
      </div>
    );
  }
}

export default App;