【问题标题】:React Hooks and ActionCableReact Hooks 和 ActionCable
【发布时间】:2019-08-09 14:47:25
【问题描述】:

尝试与 React 新的 Hooks 和 ActionCable 相处,但遇到了在尝试发送状态时无法在 Rails 中获取正确数据的问题。

我尝试在执行setState() 后立即使用send() 方法并发送我更新的数据,但由于某种原因,Rails 部分收到的数据是旧的。 例如,如果我将“Example”放在输入中,我会在 Rails 端看到“{“data”=>“Exampl”}。我想数据更新状态晚于我的请求。 如果我 send() 的值来自 e.target.value 一切正常

因此,我尝试使用新的useEffect() 挂钩并在那里发送数据。但是我在渲染页面时只得到数据。之后,我什么也没有得到,有时会收到错误RuntimeError - Unable to find subscription with an identifier。好像效果挂钩太早发送数据之类的。

我对 Hooks 和 WebSockets 还是很陌生。很想在这里得到任何帮助。我可以共享 Rails 代码,但只有一个接收器,没有别的。

第一个例子:

import React, { useState, useEffect } from "react"
import ActionCable from 'actioncable'

function Component(props) {
const [data, setData] = useState("");

const cable = ActionCable.createConsumer('ws://localhost:3000/cable');
const sub = cable.subscriptions.create('DataChannel');

const handleChange = (e) => {
 setData(e.target.value)
 sub.send({ data });
}

return (
  <input value={data} onChange={handleChange}/>
 )
}

尝试使用Effect并将send()移到那里:

  useEffect(() => {
    sub.send({ data });
  }, [data]);

我很想找到一种正确使用 React 和 ActionCable 的方法。如果可能,请使用钩子。

【问题讨论】:

    标签: javascript ruby-on-rails reactjs actioncable


    【解决方案1】:

    我正在尝试类似于 Oleg 的方法,但我无法在操作电缆中 setChannel 创建订阅回调。我必须setChannel 在回调之外但在 useEffect 挂钩内。以下是对我有用的解决方案。

    1. 在 index.js 中创建消费者,并通过 Context 将消费者提供给 App。
    index.js
    
    import React, { createContext } from 'react'
    import actionCable from 'actioncable'
    ... omitted other imports
    
    const CableApp = {}
    CableApp.cable = actionCable.createConsumer('ws://localhost:3000/cable')
    export const ActionCableContext = createContext()
    
    ReactDOM.render(
      <Router>
        ... omitted other providers
    
        <ActionCableContext.Provider value={CableApp.cable}>
            <App />
        </ActionCableContext.Provider>
    
      </Router>,
      document.getElementById('root')
    )
    
    1. 在子组件中使用电缆上下文并在 useEffect 挂钩中创建订阅;在清理中取消订阅
    import React, { useState, useEffect, useContext } from 'react'
    import { useParams } from 'react-router-dom'
    
    ... omitted code
    
    const [channel, setChannel] = useState(null)
    const { id } = useParams()
    
    const cable = useContext(ActionCableContext)
    useEffect(() => {
      const channel = cable.subscriptions.create(
        {
          channel: 'MessagesChannel',
          id: id,
        },
        {
          received: (data) => {
            receiveMessage(data)
          },
        }
      )
    
      setChannel(channel)
    
      return () => {
        channel.unsubscribe()
      }
    }, [id])
    
    const sendMessage = (content) => {
      channel.send(content)
    }
    

    【讨论】:

      【解决方案2】:

      你可以像这样在根组件注册你的电缆:

      import actionCable from 'actioncable';
      
      (function() {
        window.CableApp || (window.CableApp = {});
        CableApp.cable = actionCable.createConsumer('ws://localhost:3000/cable')
      }).call(this);`
      

      所以它可以作为全局变量使用;

      然后在您要创建通道和发送数据的任何组件中:

      const [channel, setChannel] = useState(null);
                useEffect(() => {
               CableApp.cable.subscriptions.create(
                {
                  channel: 'YourChannelName',
                },
                {
                  initialized() {
                    setChannel(this)
                  },
                },
              );
            }, []);
      
      return <button onClick={() => channel.send(some_data)} >Send counter</button>
      

      【讨论】:

        【解决方案3】:

        你的问题在这里:

        const handleChange = (e) => {
         setData(e.target.value)
         sub.send({ data });
        }
        

        setData 与 setState 类似,状态仅在渲染后更新,即在函数退出后。您正在发送当前数据而不是新数据。试试这个:

        const handleChange = (e) => {
         const newData = e.target.value;
         setData(newData)
         sub.send({ data: newData });
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-30
          • 1970-01-01
          • 2021-07-14
          • 2020-03-23
          • 2021-01-22
          • 1970-01-01
          • 1970-01-01
          • 2020-06-06
          相关资源
          最近更新 更多