【问题标题】:How to get channel messages in Elixir Phoenix to change the state of a React component?如何在 Elixir Phoenix 中获取通道消息以更改 React 组件的状态?
【发布时间】:2018-01-31 02:06:30
【问题描述】:

我试图弄清楚如何根据外部事件来更新组件的状态,在这种情况下,外部事件是来自 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. 

【问题讨论】:

  • My "this.state.chan.on" doesn't work 哪个部分不起作用?它会抛出错误吗?它根本没有被调用吗?
  • this.setState(prevstate =&gt; { return {mess: ${payload.body}} }); 这看起来像是语法错误。
  • 已编辑以反映上述两个 cmets。我可怜的 JS 的 Apols 是的,我可能在那里有语法错误,但在那之前似乎有问题....

标签: reactjs elixir phoenix-framework phoenix-channels


【解决方案1】:

在函数之外的类主体中不能有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});
    });
  }

  ...
}

这有一个问题。即使从 DOM 中卸载该组件,on 回调也会继续被触发。您应该在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);
  }

  ...
}

【讨论】:

  • 'setState(oldstate => newState)' 实际上是有效的
  • @webdeb 是的,那部分是有效的,但 return {mess: ${payload.body}} 是一个语法错误。
  • 有趣的是,我不知道是不是我,但我在 this.state.ref 中得到一个“未定义”。我确实修改了您的代码: componentDidMount() { console.log(this.state); const ref = this.state.chan.on("counter", payload => { console.log(this.state); let thebody = payload.counter; this.setState({mess: thebody}); this.state. chan.push("计数器", {body: thebody}) }); this.setState({ref: ref}); this.state.chan.push("counter", {body: "1"}) }
  • 所以我将计数器发送回通道,通道将其反弹回给我,增量为 1。更新工作正常 - 即反应正在更新 dom。我只是想知道为什么在我的版本中 this.state.ref 是未定义的。
  • this.state.ref 何时未定义?在componentWillUnmount?
猜你喜欢
  • 1970-01-01
  • 2022-01-11
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
  • 2021-05-11
  • 2023-03-26
  • 2014-05-23
  • 2021-06-05
相关资源
最近更新 更多