代码之家  ›  专栏  ›  技术社区  ›  Thomas Browne

如何在Elixir Phoenix中获取通道消息以更改React组件的状态?

  •  1
  • Thomas Browne  · 技术社区  · 8 年前

    我试图找出如何根据外部事件更新组件的状态,在本例中,外部事件是一条来自Elixir Phoenix频道的消息。

    a) 如何将通道引入组件?到目前为止,我是作为道具通过海峡的。

    b) 如何处理进入组件内部通道的消息?我的“this.state.chan.on”不起作用,看起来很笨拙。

    import socket from "./socket"
    import React from "react"
    import ReactDOM from "react-dom"
    
    socket.connect()
    
    // Now that you are connected, you can join channels with a topic:
    let channel = socket.channel("topic:subtopic", {})
    
    channel.join()
      .receive("ok", resp => { console.log("Joined successfully", resp) })
      .receive("error", resp => { console.log("Unable to join", resp) })
    
    class HelloWorld extends React.Component {
      state = {
        chan: this.props.channel,
        mess: this.props.message
      }
    
      this.state.chan.on("new_message", payload => {
        this.setState(prevstate => {
          return {mess: ${payload.body}}
        });
      })
    
    
      componentDidMount = () => {
        console.log("did mount Hello World")
      }
    
      render = () => {
        return (<h1>{this.state.mess}</h1>)
      }
    }
    
    
    ReactDOM.render(
      <HelloWorld message={1} channel={channel}/>,
      document.getElementById("hello-world")
    )
    

    编辑:

    17:55:13 - error: Compiling of web/static/js/app.js failed. L40:6 Unexpected token 
         38 |   }
         39 | 
       > 40 |   this.state.chan.on(
            |       ^
         41 | 
         42 |   componentDidMount = () => {
         43 |     console.log("did mount Hello World")
    Stack trace was suppressed. Run with `LOGGY_STACKS=1` to see the trace. 
    18:07:20 - error: Compiling of web/static/js/app.js failed. L40:6 Unexpected token 
         38 |   }
         39 | 
       > 40 |   this.state.chan.on("new_message", payload => {
            |       ^
         41 |     this.setState(prevstate => {
         42 |       return {mess: ${payload.body}}
         43 |     });
    Stack trace was suppressed. Run with `LOGGY_STACKS=1` to see the trace. 
    18:07:22 - error: Compiling of web/static/js/app.js failed. L40:6 Unexpected token 
         38 |   }
         39 | 
       > 40 |   this.state.chan.on("new_message", payload => {
            |       ^
         41 |     this.setState(prevstate => {
         42 |       return {mess: ${payload.body}}
         43 |     });
    Stack trace was suppressed. Run with `LOGGY_STACKS=1` to see the trace. 
    
    1 回复  |  直到 8 年前
        1
  •  2
  •   Dogbert    8 年前

    你不能有 this.state.chan.on(...) 在类体之外的函数。不过,您可以将所有这些代码放在构造函数中。此外,您的 setState

    class HelloWorld extends React.Component {
      constructor(props) {
        super();
    
        this.state = {
          chan: props.channel,
          mess: props.message
        };
    
        this.state.chan.on("new_message", payload => {
          this.setState({mess: payload.body});
        });
      }
    
      ...
    }
    

    不过,这有一个问题。这个 on 即使该组件从DOM中卸载,回调也会一直被触发。您应该在中订阅邮件 componentDidMount componentWillUnmount :

    class HelloWorld extends React.Component {
      constructor(props) {
        super();
    
        this.state = {
          chan: props.channel,
          mess: props.message
        };
      }
    
      componentDidMount() {
        const ref = this.state.chan.on("new_message", payload => {
          this.setState({mess: payload.body});
        });
        this.setState({ref: ref});
      }
    
      componentWillUnmount() {
        this.state.chan.off("new_message", this.state.ref);
      }
    
      ...
    }