1

我试图弄清楚如何根据外部事件来更新组件的状态,在这种情况下,外部事件是来自 Elixir Phoenix 频道的消息。

所以基本上,我有一个简单的 h1 标签,它必须始终反映进入频道的最新内容。所以有两个相互关联的问题:

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")
)

这样做的公认方式是什么?如何从通道或套接字或其他任何东西获取消息,在反应之外和用户界面之外生成,以影响组件的状态,以及相关的,我如何首先将外部事件通过管道传递到组件中?将通道放入组件中是否正确?因为这似乎也将通道的输出限制为仅影响该组件,而不是我可能希望它影响的其他独立组件。

编辑:这是编译错误消息。是的,我知道我的 JS 可能不正确,但我在第一个 this.state.chan.on 上就出现了语法错误:

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. 
4

1 回答 1

2

您不能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);
  }

  ...
}
于 2017-08-22T17:56:04.550 回答