我有一个React应用,它的作用是选择自己的冒险事物,因此它会打印一条消息,然后用户单击一个按钮做出决定,然后确定下一条消息。
某些消息没有相关的决策,新消息应该自动打印出来。在我当前的设置下,当用户必须单击一个按钮以显示下一条消息时,它可以很好地工作,但是当应该自动显示该消息时,它实际上是在重复显示下一条消息,直到崩溃为止。
我尝试了很多事情都给出相同的结果,应该只显示一次的消息会显示多次,直到应用程序崩溃为止。
请注意,决策的工作方式是将整数列表(每个整数代表下一个孩子的名字)发送到服务器,然后使用该列表遍历一棵树-就像我说的那样当玩家选择一个按钮,然后根据选择的按钮向列表添加一个整数时,效果很好。
当没有按钮时,我试图建立一种方法,该方法会自动将0
自动添加到列表中(因为如果没有选择,它只有一个孩子,第0个孩子)。 / p>
这是我的代码,有按钮时使用onDecide
方法,无按钮时使用onNonDecide
方法-我本来只是尝试使用onDecide
方法并尝试将它们分开以查看是否可行,但还是存在相同的问题。
还要注意generateDecisions
方法,因为它有一个if
语句,该语句在没有决定要更改时会改变行为。
class Home extends Component {
constructor(props) {
super(props);
this.state = {
previouslyPlayed: [],
currentNode: {
id: 1,
text: 'Ah-- what the hell? Stupid thing.',
decisions: [
{
id: 'n1d1',
text: 'Who is this?',
whichChild: 0,
attitude: 0
},
{
id: 'n1d2',
text: 'What the hell yourself.',
whichChild: 0,
attitude: 0
}
],
speaker: 0,
checkpoint: true
},
decisionList: [0]
};
this.onDecide = this.onDecide.bind(this);
this.onNonDecide = this.onNonDecide.bind(this);
}
// Generate the previous messages to be displayed on the screen
generateMessages() {
let currentPrevious = this.state.previouslyPlayed;
if (currentPrevious.indexOf(this.state.currentNode.text) < 0) {
currentPrevious.push(this.state.currentNode.text);
}
return currentPrevious.map((text) =>
<Message key={currentPrevious.indexOf(text)} text={text}/>
);
}
// Generate the current decision that the play must make
generateDecision() {
if (this.state.currentNode.decisions.length <= 0) {
let ignore = this.onNonDecide();
} else {
return <Decision decisions={this.state.currentNode.decisions} onDecide={this.onDecide}/>;
}
}
updatePreviouslyPlayed(text) {
let previouslyPlayed = this.state.previouslyPlayed;
previouslyPlayed.push(text);
this.setState({previouslyPlayed: previouslyPlayed});
}
updateDecisionList(whichChild) {
let decisionList = this.state.decisionList;
decisionList.push(whichChild);
this.setState({decisionList: decisionList});
}
async onDecide(answer) {
//Update the state to reflect the decision made
this.updatePreviouslyPlayed(answer.text);
this.updateDecisionList(answer.whichChild);
let body = { decisionList: this.state.decisionList };
let currentNode = await (await fetch('http://localhost:8080/decide', {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body),
})).json();
this.setState({currentNode: currentNode});
}
async onNonDecide() {
this.updateDecisionList(0);
let body = { decisionList: this.state.decisionList }
let currentNode = await (await fetch('http://localhost:8080/decide', {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify(body),
})).json();
this.setState({currentNode: currentNode});
}
render() {
return (
<div>
<Container id={'Application'}>
{this.generateMessages()}
{this.generateDecision()}
</Container>
</div>
);
}
}
export default Home;
我要执行的操作是一次设置currentNode
,然后调用generateMessages
和generateDecisions
,然后打印出新的Message
,并可能新的Decision
。它要做的是开始相同的Message
打印数百次。
答案 0 :(得分:2)
问题在于您有副作用,这些副作用会改变在render
方法中调用的状态。
render()函数应该是纯函数,这意味着它不会修改组件状态,每次调用时都返回相同的结果,并且不与浏览器直接交互。 -React Docs
例如,此路径render() -> this.generateDecision() -> this.onNonDecide() -> this.setState() -> render()
(重复一遍,可能是一个无限循环,我没有考虑所有可能的路径,仅举一个例子)。
您可能会遇到的另一个问题是,没有发生重新渲染或其他意外行为,就像在generateMessages
中那样发生了突变状态。 previouslyPlayed
数组已被currentPrevious.push
突变。