在 ReactJS 应用程序中将字符串转换为 JSON 对象时出错
Posted
技术标签:
【中文标题】在 ReactJS 应用程序中将字符串转换为 JSON 对象时出错【英文标题】:Error during conversion of a string to JSON object in ReactJS application 【发布时间】:2018-02-17 06:55:51 【问题描述】:作为我学习 ReactJS 的持续努力的一部分,我正在开发一个简单的页面,它将呈现如下趋势列表:
单击“获取趋势”按钮后,趋势列表会通过 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 子级无效...
Google 搜索将我引向另一个兔子洞!有人可以提供任何其他解决方案供我尝试吗?
【问题讨论】:
【参考方案1】:查看您的代码(以及您刚刚学习的注释),让我添加一些 cmets 如何改进它。
使用带有类属性的箭头函数可确保始终以组件作为this
的值调用该方法,这意味着此处的手动绑定是多余的。所以你可以摆脱下面的行。
this.handleOnClick = this.handleOnClick.bind(this);
还要去掉 TrendTable
中丑陋的 for
循环,并将其替换为 map 函数。
class TrendTable extends Component
render()
return (
<table>
<tbody>this.props.trends.map(trend =>
<TrendRow key=i onerow=trend/>)
</tbody>
</table>
);
You can read more 如果您要避免常规的for
循环,您有哪些替代方案。
要预填充您的 trends
数组,更好的方法是使用 componentDidMount
react 生命周期方法。要深入了解this 文章。
而且我认为最好创建更新按钮(而不是获取趋势),它应该用后端的新部分完全重写你的趋势列表,以防万一你需要(但请确保这一点取决于你)。
现在只要初始化默认状态就可以不用在组件内部使用构造函数了,所以可以使用
state = ....;
就在您的组件内部,不使用构造函数。但请确保您使用的是stage-2 preset。
所以考虑到上面的 cmets,这里是 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>
);
-
关于您的问题本身。正如许多其他人已经提到的那样,是的,在 JSX 中无法使用对象,因此您必须先对其进行转换(例如转换为数组)。
例如
var array = Object.values(jsonobject).map(value => ...);
// and then in JSX
<div>array</div>
希望这一切都有意义。
【讨论】:
非常感谢您提供详细的回复。这是一个信息宝库,我需要一些时间才能吸收所有这些信息。我的页面现在按预期加载趋势列表。不过我确实有一点意见:我使用丑陋的 for 循环,使用用户选择的计数器变量来选择趋势的子集。我仍在尝试弄清楚如何使用地图和过滤器功能来完成此任务。如果这是微不足道的,请不要发表评论,我希望自己能够弄清楚。【参考方案2】:jsonobject
是一个对象。
React 不知道如何渲染它。
你可以把它转换成一个数组然后渲染它。
var jsonArray = Object.keys(jsonobject).map(function(k)
return jsonobject[k];
);
JSX:
<td>jsonobject</td>
【讨论】:
您的代码 sn-p 真的很有帮助。我的 JSX 如下所示:“使您的第一种方法有效的简单解决方案是通过在第一次渲染期间不尝试解析 JSON 来规避错误:
var jsonobject = this.props.onerow ? JSON.parse(this.props.onerow) : ;
正如其他人所说,您不能直接渲染对象。出于测试目的,请将<td>jsonobject</td>
替换为<td>jsonobject.id</td>
。
【讨论】:
【参考方案4】:如果您记录初始行,以及 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 对象。
【讨论】:
【参考方案5】:我在结合用户提供的建议后提供了更新的代码。这可能并不完美,但完成了我想要的。
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;
【讨论】:
以上是关于在 ReactJS 应用程序中将字符串转换为 JSON 对象时出错的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ReactJS 中将带有属性的 CSS 转换为 MaterialUI 样式