setState在ReactJS中有延迟

时间:2017-07-30 23:46:22

标签: reactjs setstate

我想通过读取JSON文件来实现对话系统,这里是:`

{
   "start": {
      "dialogue1": {
        "text": "Hi! How are you?"
      },
      "dialogue2": {
        "text": "My name is Bill."
      },
      "dialogue3": {
        "text": "What is your name?"
      },
      "dialogue4": {
        "text": "Nice to meet you"
      }
    }
}

这是读取JSON文件的组件:

import React, { Component } from 'react'
import Speaking from './Speaking'
import dialogues from './dialogues/dialogues.json';


class myClass extends Component {
  constructor(props) {
    super(props);
    this.goToDialogue = this.goToDialogue.bind(this)

    //starts with empty dialogue
    this.state = {
      dialogue: ''
    };
  }

  componentDidMount() {
    //starts first dialogue at the beginning
    this.goToDialogue('start')
  }

  goToDialogue(dialogueName) {
    //loop through dialogue JSON and update the state
    for (let dialogue in dialogues[dialogueName]) {
      this.setState( {dialogue : dialogues[dialogueName][dialogue].text} )
    }
  }

  render() {
    return (
        //give Speaking's component the new dialogue to display
        <Speaking dialogue={this.state.dialogue} />
    );
  }

}

export default myClass

最后是将显示文本的Speaking组件

import React, { Component } from 'react';

class Speaking extends Component {
  constructor(props) {
    super(props);
    this.showText = this.showText.bind(this)
  }

  componentDidUpdate() {
    //showText() will display the message it receives into the paragraph letter by letter
    this.showText(this.props.dialogue, 0, 75 )
  }

  showText(message, index, interval) {
    if (index < message.length) {
      this.speak.innerHTML += message[index++]
      setTimeout( () => { this.showText(message, index, interval); }, interval)
    }
  }

  render() {

    return (
      <p className="speak" ref={node => this.speak = node} ></p>
    );
  }
}

export default Speaking;

问题是myClass.state.dialogue将进行最后一次循环迭代,因此它只显示最后一个对话行。 我想要的正确结果是逐个显示每个对话行(换句话说,setState是对话),每次迭代之间有一个延迟。我想过在setState上使用setTimeOut,但它没有成功。

知道怎么排序吗?谢谢!

1 个答案:

答案 0 :(得分:2)

您可以使用Speaking组件中的回调来了解当前对话何时被完全说出。

class myClass extends Component {
  constructor(props) {
    super(props);
    this.goToDialogue = this.goToDialogue.bind(this)
    this.handleHasSpoken = this.handleHasSpoken.bind(this);

    //starts with empty dialogue
    this.state = {
      dialogue: '',
      dialogueIndex: 0
    };
  }

  componentDidMount() {
    //starts first dialogue at the beginning
    this.goToDialogue('start')
  }

  goToDialogue(dialogueName) {
    const { dialogueIndex } = this.state;
    this.setState( { dialogue: dialogues[dialogueName][dialogueIndex].text });
  }

  handleHasSpoken() {
     const { dialogueIndex } = this.state;

     //insert logic to check if last dialogue
     this.setState({ 
         dialogueIndex: dialogueIndex+1,
         dialogue: dialogues[dialogueName][dialogueIndex+1]
     });
  }

  render() {
    return (
        //give Speaking's component the new dialogue to display
        <Speaking 
            dialogue={this.state.dialogue}
            hasSpoken={this.handleHasSpoken}
        />
    );
  }

}

然后在Speaking中,只需在消息末尾调用回调

class Speaking extends Component {
  constructor(props) {
    super(props);
    this.showText = this.showText.bind(this)
  }

  componentDidUpdate() {
    //showText() will display the message it receives into the paragraph letter by letter
    this.showText(this.props.dialogue, 0, 75 )
  }

  showText(message, index, interval) {
    if (index < message.length) {
      this.speak.innerHTML += message[index++]
      setTimeout( () => { this.showText(message, index, interval); }, interval)
    } else {
        this.props.hasSpoken();
    }
  }

  render() {

    return (
      <p className="speak" ref={node => this.speak = node} ></p>
    );
  }
}