反应挂钩和ActionCable

时间:2019-08-09 14:47:25

标签: javascript ruby-on-rails reactjs actioncable

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

我尝试在完成send()后立即使用setState()方法并发送我的更新数据,但是由于某些原因,在Rails部分接收的数据已旧。 例如,如果我在输入中输入“ Example”,那么我会在Rails端看到“ {{data” =>“ Exampl”}。我认为数据更新状态要晚于请求的执行时间。 如果我send()的{​​{1}}值一切正常

因此,我尝试使用新的e.target.value挂钩并在那里发送数据。但是渲染页面时我只能得到数据。之后,我什么也没得到,有时会收到错误useEffect()。似乎效果钩子太早发送数据了。

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

第一例:

RuntimeError - Unable to find subscription with an identifier

尝试使用useEffect并将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}/> ) } 移到那里:

send()

我很想找到一种正确使用React和ActionCable的方法。并尽可能使用钩子。

3 个答案:

答案 0 :(得分:0)

您可以像这样在根组件上注册电缆:

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from scipy.integrate import solve_bvp

def fun(x, y):
    return np.vstack([y[1], y[2], y[3], np.ones(y.shape[1])])

def bc(ya, yb) :
    return np.array([ya[0], ya[1], yb[0], yb[1]])

xmesh = np.linspace(0, 10, 100)
y = np.zeros((4, len(xmesh)))
sol = solve_bvp(fun, bc, xmesh, y)

plt.figure()
for i in range(4):
    plt.plot(xmesh, sol.sol(xmesh)[i], label = str(i+1))
plt.legend()

因此它将用作全局变量;

,然后在要创建频道并发送数据的任何组件中:

import actionCable from 'actioncable';

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

答案 1 :(得分:0)

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

  1. 在index.js中创建使用者,并通过上下文将使用者提供给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. 在子组件中使用cable上下文,并在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 :(得分:0)

您的问题在这里:

@echo off    
rem run cmd with \u -for utf 16    
setlocal EnableDelayedExpansion EnableExtensions    
SET "SourceParentDir=C:\Export"    
set back=%cd%    
    
set "files="    
set "originalPDF="    
    
rem loop through subdirectories    
for /d %%i in (%SourceParentDir%\*) do (    
        
    rem get filepath of master pdf    
    set "originalPDFpath=%%~i"    
    set "originalPDFpath=!originalPDFpath:~0,-1!.pdf"    
        
    rem get filename of master pdf    
    set "originalPDF=%%~nxi"    
    set "originalPDF=!originalPDF:~0,-1!.pdf"    
        
    rem traverse subdirectories    
    cd "%%i"    
        
    rem get list of pdf files    
    (for /R %%a in (*.pdf) do (    
        set "files=!files! "%%~fa""    
    )    
        
    rem combine pdf files    
    pdftk "!originalPDFpath!" !files! cat output "c:\test\!originalPDF!"        
    set "files="    
    )    
)    
cd %back%    

setData 就像 setState 一样,状态只在渲染之后更新,即在函数退出之后。您发送的是当前数据而不是新数据。试试这个:

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