Fabian Omobono
Fabian Omobono

Reputation: 101

Can not setState on Websocket.onmessage

I am trying to implement a chat page for my app.

I am using react and django channels. I am having a problem with rendering the message on Websocket.onmessage Here's the code that gives me the error

// ask for the user
const request = new XMLHttpRequest()
const csrftoken = Cookies.get('csrftoken');
request.open('POST', "/get_user", true)
request.setRequestHeader("X-CSRFToken", csrftoken);
request.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
request.onload = function () {
  const user = JSON.parse(request.responseText).user
  const room_name = 'lobby'
  // channels stuff
  const chatSocket = new WebSocket(
    'ws://' + window.location.host +
    '/ws/chat/' + room_name + '/');

  chatSocket.onclose = function(e) {
    console.error("Socket closed unexpectedly.", e)
  }


  function Convo_bubble(props){
    if (props.user !== 'Customer Support'){

      return(
        <div className='bubble_container'>
          <p className='bubble_info'> {props.user} </p>
          <div className='bubble'>{props.message}</div>
        </div>
      )

    }
    else {

      return (
        <div className='bubble_container_admin'>
          <p className='bubble_info'> {props.user} </p>
          <div className='bubble_admin'>{props.message}</div>
        </div>
      )

    }
  }


  class Chat_app extends React.Component {
    constructor(props) {
      super(props)
      this.state = {
        messages: [{message: 'Hi, how can I help you today?', user:'Customer Support'}],
      }

    }

    addMessage(){
      chatSocket.onmessage = function(e) {
        const data = JSON.parse(e.data);
        const sender = data['sender']
        var message = data['message']
        console.log(data)
        if (message !== ''){
          
          this.setState({
            messages: [...this.state.messages, {message: message, user: user}],
          })
          document.getElementById('message_input').value = ''
          }
      }
      const text = document.getElementById('message_input').value
        if (text !== ''){
          chatSocket.send(JSON.stringify({
              'message': text,
              'user': user,
          }));
        }
      }

    checkEnter(e) {
      if (e.key === 'Enter'){
        this.addMessage()
      }
    }

    componentDidUpdate() {
      document.getElementById('scrollto').scrollIntoView()
    }
    render () {

      return (
        <div>
          <h1>Questions? A customer reppresentative will be happy to assist you</h1>
          <div className="chat_container">
            <div className="conversation_container">
              {this.state.messages.map(message => <div><Convo_bubble
              message={message.message} user={message.user} /><br /> </div>)
            }
            <div id='scrollto'></div>
            </div>
            <div className="Compose_message_container">
              <input  onKeyPress={() => this.checkEnter(event)} id='message_input' type='text' placeholder="Type your message here..."/>
              <button id="submit_message_button" onClick={() => this.addMessage()}><i className="fa fa-send"></i></button>

            </div>
          </div>
        </div>
      )
    }
  }


  ReactDOM.render(
    <Chat_app />, document.querySelector("#root")
  )
  // focus on the input bar
  document.querySelector("#message_input").focus()


}
request.send()

this is the error message in the console: Uncaught TypeError: Cannot read property 'messages' of undefined

the error get's caused by this.setState({....}) Any ideas where I am wrong?

Upvotes: 2

Views: 1053

Answers (1)

sdkcy
sdkcy

Reputation: 3548

you need to bind addMessage function in constructor with ‘this’ parameter. So, your function has the context of the class.

constructor(props) {
  super(props)
  this.state = {
    messages: [{message: 'Hi, how can I help you today?', user:'Customer Support'}],
  }
  this.addMessage = this.addMessage.bind(this);
}

And also change the function to fat arrow to bind the context automatically

 chatSocket.onmessage = (e) => {…}

Upvotes: 1

Related Questions