作为我不断努力学习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: Unexpected token u in JSON at position 0
…
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)}));
}
}
我收到错误消息:
Objects are not valid as a React child…
谷歌搜索让我陷入另一个兔子洞!有人可以为我提供任何其他解决方案吗?
解决方法:
看看你的代码(以及你刚刚学习的笔记),让我添加一些评论,告诉你如何改进它.
>使用带有类属性的箭头函数可确保始终使用组件作为此值调用方法,这意味着此处的手动绑定是多余的.所以你可以摆脱下面的界限.
this.handleOnClick = this.handleOnClick.bind(this);
>还要摆脱TrendTable中丑陋的for循环,并将其替换为map功能.
class TrendTable扩展了Component {
render(){
回来(
<表>
< tbody> {this.props.trends.map(trend =>
< TrendRow key = {i} onerow = {trend} />)}
< / tbody的>
< /表>
);
}
}
You can read more关于你要避免常规循环的替代方案.
>对于预填充趋势数组,更好的方法是使用componentDidMount反应生命周期方法.深入深入查看this文章.
我认为最好创建更新按钮(而不是获取趋势),如果需要,应该使用后端的新部分完全重写您的趋势列表(但确定这一点取决于您).
>现在,如果只需要初始化默认状态,则不必在组件内部使用构造函数方法,因此可以使用
state = {….};只是在你的组件内部没有使用构造函数.但请确保您使用的是stage-2 preset.
因此,考虑到上面的评论,这里是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>
希望这一切都有道理.