从API响应中获取数据文本,并在与React的聊天中进行呈现

时间:2018-12-11 15:20:05

标签: reactjs rest

我有一个聊天UI,用户应该在其中输入文本并从API响应服务接收一些数据。用户界面工作正常,并且在聊天中显示了用户文本,但是以JSON格式接收的来自API的响应根本没有出现在聊天中(甚至没有来自API的错误消息,该消息应该出现在“消息”中字段,这是应该在其中显示结果的字段。)据我所知,一切都配置正确,但是我不知道render方法是否有些混乱。

注意:开始时处于聊天状态的预配置消息仅用于测试目的。

我发布的第一段代码的componentDidUpdate()方法下的Fetch操作。

 import React from "react";
import ReactDOM from "react-dom";
import "./App.css";

import Message from "./Message.js";

class Chatroom extends React.Component {
  constructor(props) {
    super(props);

    this.state = {

      chats: [
        {
          username: "clientUser",
          content: <p>Hello World!</p>,
          img:
            "http://***.jpg"
        },
        {
          username: "user2",
          content: <p>Hi,my name is user2.What's up ??</p>

        },
        {
          username: "user3",
          content: <p>Hi,my name is user3.What's up ??</p>
        },
        {
          username: "user4",
          content: <p>Hi,my name is user4.What's up ??</p>
        },
        {
          username: "userN",
          content: <p>Hi,my name is userN.What's up ??</p>,
          img: "http://***.jpg"
        },
        {
          username: "user5",
          content: <p>Hi,my name is user5.What's up ??</p>
        },
        {
          username: "user6",
          content: <p>Hi,my name is user6.What's up ??</p>
        },
        {
          username: "user7",
          content: <p>Hi,my name is user7.What's up ??</p>
        }
      ]
    };

    this.submitMessage = this.submitMessage.bind(this);
  }

  componentDidMount() {
    this.scrollToBot();

  }

  componentDidUpdate() {
    this.scrollToBot();


    fetch(
      "https://****",
      {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"

        },
        body: JSON.stringify({
          inputText: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>
        })
      }
    ).then(response => response.json())
      .then(parsedJSON =>
        parsedJSON.results.map((
          user
        ) => ({

          username: "BotResponse",
          content: `${user.message}',
          img: "http://***.jpg"
        }))
      )
      .then(chats =>
        this.setState({
          chats
        })
      )
      .catch(error => console.log("parsing failed", error));


  }

  scrollToBot() {
    ReactDOM.findDOMNode(this.refs.chats).scrollTop = ReactDOM.findDOMNode(
      this.refs.chats
    ).scrollHeight;
  }

提交消息方法:

submitMessage(e) {

        e.preventDefault();




        this.setState(
          {
            chats: this.state.chats.concat([

              {
                username: "clientUser",

                content: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>,

                img: "http://***.jpg"
              }


            ])
          },
          () => {

            ReactDOM.findDOMNode(this.refs.msg).value = "";
          }

        );


      }  

render方法:

  render() {

    const username = "clientUser";
    const { chats } = this.state;

    return (
      <div className="chatroom">
        <h3>
          Title
        </h3>

        <ul className="chats" ref="chats">
          {chats.map((
            chat //Defines message component
          ) => (
            <Message chat={chat} user={username} />
          ))}
        </ul>
        <form className="input" onSubmit={e => this.submitMessage(e)}>
          <input type="text" ref="msg" />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default Chatroom;

2 个答案:

答案 0 :(得分:1)

问题出在你的思维方式上。您的想法就像是编写带有JS增强功能的纯HTML一样。 React是一个根本的概念转变。您需要忘记很多从普通的JS中学到的知识,才能学习React。在React中,您不会让HTMLElement进行操作,而是使用本地/全局状态和组件属性来声明您的UI。生成的代码更加高效,可维护且无故障。

要回到实际问题,您不应该使用ref来获取输入值。而是使用onChange设置邮件的状态,并在以后需要时进行检索。

例如:

export class MessageComposer extends React.Component {

  state = {
    fields: {
      message: ""
    }
  }

  clearField = fieldName => {
    this.setState({
      fields: {
        [fieldName]: ""
      }
    })
  }

  onInputChange = e => {
    this.setState({
      fields: {
        [e.target.name]: e.target.value
      }
    })
  }

  sendMessage = () => {
    const { fields: { message } } = this.state

    // Here you send the message contained into `message`.
    console.log(message)

    // Then you clean the message input value.
    this.clearField("message")
  }

  render () {
    const { fields: { message } } = this.state
    return (
      <div className="MessageComposer__container">
        <input 
          type="text"
          name="message"
          value={message}
          onChange={this.onInputChange}
        />
        <button onClick={this.sendMessage}>
          Submit
        </button>
      </div>
    )
  }

}

编辑:刚刚看到您的提取代码包含JSX。 WTF?

尝试更改以下内容:

body: JSON.stringify({
  inputText: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>
})

具有无JSX的版本。传递React组件没有任何意义,因为JSON.stringify甚至无法序列化函数(好的,您会收到将'Function'或'[Object object]'放入{{1} }在您的后端上)。

像这样的东西

inputText

此外,如果由于任何原因React无法找到您的引用(即组件返回body: JSON.stringify({ inputText: ReactDOM.findDOMNode(this.refs.msg).value }) 或任何其他原因),null都会抛出或返回inputText

如果按照我上面的建议重构代码,则可以执行以下操作:

undefined

答案 1 :(得分:0)

关于您的代码,有很多要讨论的内容。为了使答案简单而集中,我只想谈谈您的fetch api call,以及为什么您可能看不到前端的内容。

首先,我建议研究React文档中的生命周期方法。您可以找到here。如果该链接断开,则只需转到React的文档页面并搜索“ LifeCycle Methods”。

我提出这个问题的原因是,您每次post {em}每次都会更新数据,而不是在用户提交聊天消息时更新。因此,在用户提交您的那一刻,您就会调用onSubmit的{​​{1}}函数。设置状态将更新帖子。因此,在代码中的任何位置,当您更改状态或更改组件的props时,DOM都会更新,并且setState将被触发并再次发布。

将您的post api调用放置在componentDidUpdate函数中。从此更新您的表单:

onSubmit

此更新的onSubmit函数:

 submitMessage(e) {
    e.preventDefault();
    this.setState(
      {
        chats: this.state.chats.concat([

          {
            username: "clientUser",

            content: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>,

            img: "http://***.jpg"
          }
        ])
      },
      () => {

        ReactDOM.findDOMNode(this.refs.msg).value = "";
      }
    );
  }

后端

您要确认这确实是 保存到您的数据库中(可能看起来很明显,但是请仔细检查一下它是否保存了您想要的 并返回了正确的信息,以正确的格式显示在后端上。这可能是问题所在。将您的响应记录到后端控制台,并确保它正确返回了所有内容。

前端

看看如何在获取呼叫中设置状态。我不太确定您是如何发送数据的,但这是使用axios进行后期提取调用的示例。

submitMessage(e) {
    e.preventDefault();
    fetch(
  "https://****",
  {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json"

    },
    body: JSON.stringify({
      inputText: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>
    })
  }
).then(response => response.json())
  .then(parsedJSON => {
    parsedJSON.results.map((
      user
    ) => ({

      username: "BotResponse",
      content: `${user.message}',
      img: "http://***.jpg"
    }))
   }
  )
  .then(chats =>
    this.setState({
      chats
    })
  )
  .catch(error => console.log("parsing failed", error));

   //for the sake of readability and debugging, you might want to store 
   that obj in a local variable here and put that variable in place of ...[]
    this.setState(
      {
        chats: [
          ...this.state.chats,
          {
            username: "clientUser",

            content: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>,

            img: "http://***.jpg"
          }
        ]
      },
      () => {
        ReactDOM.findDOMNode(this.refs.msg).value = "";
      }
    );
  }

我真的没有什么可以建议的了。我不太确定您要使用提供的资源来实现什么。

注意

在整个代码中您正在做一些事情,我不确定您需要做。但是,我没有在这个答案中解决这个问题,因为我不确定您的项目是什么以及您想要的结果。但这应有助于解决不渲染的问题。如果没有,请查看如何在axios.post("http://****", { data: this.state.data, more: this.state.more, etc: { example: "of", object: this.state.obj } }) .then(response => { if (response.status === 200) { //do something with response.data //this.setState({ data: response.data}) } }); 中设置状态。

希望这会有所帮助。

编辑

我认为您的api调用不需要三个fetch api call。解析json之后,您可以在此处设置状态。

编辑2

上面的来源没有给出期望的结果。提取api调用未将数据返回到第二个then调用,因为来自第一个then调用的数据。这是更新的.then函数。

submitMessage