首页 > 解决方案 > 使用 React JS 和 WebSocket 实时更新价格

问题描述

我正在构建一个简单的网站,它使用 websocket 从 API 检索实时价格并在收到数据时更新 UI。为此,我正在使用 ReactJS 和 WebSocket。这是我的 websocket 代码:

const WebSocketContext = createContext(null)

export {WebSocketContext}

const ENDPOINT = ... 

export default ({children})=>{
    let socket;
    let ws;

    const subscribe = (ticker)=>{
        const payload = {
            'type':'subscribe',
            'symbol': `${ticker}`
        }
        waitForConnection(()=>socket.send(JSON.stringify(payload)))
    }

    const unsubscribe = (ticker)=>{
        const payload = {
            'type':'unsubscribe',
            'symbol': `${ticker}`
        }
        waitForConnection(()=>socket.send(JSON.stringify(payload)))
    }

    if (!socket){
        socket = new WebSocket(ENDPOINT) 

        socket.onopen = ()=> console.log('Connection opened')

        socket.onclose = ()=> console.log('Connection CLosed')

        ws = {
            socket: socket,
            subscribe,
            unsubscribe
        }
    }

    const waitForConnection = (callback)=>{
        if(socket.readyState === 1){
            callback()
        }else {
            setTimeout(()=>{waitForConnection(callback)}, 500)
        }
    }

    return (
        <WebSocketContext.Provider value={ws}>
            {children}
        </WebSocketContext.Provider>
    )

}

这是我的组件的代码:

const TopListItem = ({ticker})=>{
   
    const [stockData, setStockData] = useState()

    const ws = useContext(WebSocketContext)

    // Retrieve stock data like price
    useEffect(()=>{
      
        const subscribe = async ()=> ws.subscribe(ticker)

        const unsubscribe = async () => ws.unsubscribe(ticker)

        subscribe()

        ws.socket.onmessage = (msg)=>{
            const message = JSON.parse(msg.data)
            if(typeof message.data !== 'undefined'){
                // Retrieve symbol
                const symbol = message.data[0].s
                if(symbol===ticker){
                    // Retrieve price
                    const price = message.data[0].p
                    // Update price
                    setStockData(oldData=>({...oldData, price:price}))
                }
            }
        }

        return ()=> unsubscribe()
    },[])

    
    return(
        <div >
                <div >
                    <span className='ticker'>{ticker}</span>
                </div>
                <div>
                    <span>${stockData && stockData.price}</span>
                </div>
        </div>
    )
}

const TopList = ({user})=>{

    const [listItems, setListItems] = useState([])

    ...

    return(
        <div>
            {listItems && listItems.map(stock=>{
                return <TopListItem key={stock.ticker} ticker={stock.ticker} />
            })}
        </div>
    )   
}
export default TopList

假设我有 3 只股票我想收到价格。对于每只股票,我都会渲染一个TopListItem组件,我会在其中更新数据。我遇到的问题是只有第三个组件更新了价格。只有第三个组件使用setStockData()更新状态。其余不更新。

图片

这是三个组件。只有第三个 ( SPY ) 更新其价格。

为什么会这样?任何帮助将不胜感激。

标签: javascriptreactjswebsocketuse-effect

解决方案


推荐阅读