作为我不断努力学习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孩子无效......
谷歌搜索让我陷入另一个兔子洞!有人可以为我提供任何其他解决方案吗?
答案 0 :(得分:3)
查看您的代码(以及您刚学习的笔记),让我添加一些评论,说明如何改进它。
使用带有类属性的箭头函数可确保始终使用组件作为this
的值调用方法,这意味着此处的手动绑定是多余的。所以你可以摆脱下面这一行。
this.handleOnClick = this.handleOnClick.bind(this);
还要摆脱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
循环,那么您有什么替代方案。
为了预先填充trends
数组,更好的方法是使用componentDidMount
反应生命周期方法。要深入了解stage-2 preset文章。
我认为最好创建更新按钮(而不是获取趋势),如果需要,应该使用后端方面的新部分完全重写您的趋势列表(但确定这一点取决于您)
现在你不必在组件中使用构造函数方法,如果你只需要初始化默认状态,那么你可以使用
state = {....};
只是在组件内部没有使用构造函数。但请确保您使用的是{{3}}。
因此,考虑到上述评论,这里是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>
);
}
}
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;