1

At the moment I'm trying to write a simple chat application using React and SockJS. The problem I'm having is that I can't find a way for the state of my React class to change when socket.onmessage is triggered. Here's what I've written so far:

/** @jsx React.DOM */

class Chatbox extends React.Component {
    constructor() {
        this.state = { messages: [] };
    }

    addMessage(message) {
        let messages = this.state.messages;
        message = "<span className=\"chat-message\">" + message + "</span>";
        messages.push(message);
        this.setState({ messages: messages });
    }

    clearChatbox() {
        this.setState({ messages: [] });
    }

    render() {
        return (
            <div class="chatbox">
                {this.state.messages.join("<br />")}
            </div>
        );
    }
}

If I missed any other mistakes, I'd appreciate it if you could let me know.

Edit: The main problem here isn't the bindings I missed (which was just a dumb mistake on my part), but making the messages received by SockJS usable by the component itself.

Update: Alt solves the issue well for my case. Where adding messages is handled by ChatboxActions when the socket connection receives a message:

import React from 'react';
import ChatboxActions from '../actions/ChatboxActions';
import ChatboxStore from '../stores/ChatboxStore';
import connectToStores from 'alt/utils/connectToStores';

@connectToStores
class ChatBox extends React.Component {
    constructor() {
        super();
    }

    static getStores() {
        return [ChatboxStore];
    }

    static getPropsFromStores(props) {
        return ChatboxStore.getState();
    }

    static clearChatbox() {
        alt.recycle(ChatboxStore);
    }

    render() {
        <div className="chatbox">
            {this.props.messages}
        </div>
    }
}
kpimov
  • 13,632
  • 3
  • 12
  • 18
  • 1
    you are missing binding. add `this.addMessage = this.addMessage.bind(this);` to your constructor. Same for others – knowbody Jun 30 '15 at 15:12
  • possible duplicate http://stackoverflow.com/questions/31141444/reactjs-with-es6-this-props-is-not-a-function-when-i-communicate-two-components – knowbody Jun 30 '15 at 15:48

1 Answers1

0

like knowbody said.... try this:

class Chatbox extends React.Component {
    constructor(props) 
        super(props);
        this.clearChatbox = this.clearChatbox.bind(this);
        this.addMessage = this.addMessage.bind(this);
        this.componentDidMount = this.componentDidMount.bind(this);
        this._handleMessage = this._handleMessage.bind(this);
        this.state = { messages: [] };
        this._sock = new SockJS(/* put url here */);
    }

    componentDidMount() {
        this._sock.onmessage = this._handleMessage;
    }

    _handleMessage(e) {
        this.addMessage(e.data);
    }

    addMessage(message) {
        let messages = this.state.messages;
        message = `<span className="chat-message">${message}</span>`;
        messages.push(message);
        this.setState({ messages });
    }

    clearChatbox() {
        this.setState({ messages: [] });
    }

    render() {
        return (
            <div class="chatbox">
                {this.state.messages.join("<br />")}
            </div>
        );
    }
}
marcel
  • 2,967
  • 1
  • 16
  • 25
  • 1
    This doesn't answer to the OP's question – Paolo Moretti Jun 30 '15 at 15:46
  • In a way it does, since it solves the problem of not being able to use the connection inside the class, but I don't like the idea of it being bound to this when I don't plan on it being used solely for the chatbox itself. – kpimov Jun 30 '15 at 17:18