为什么 SignalR 在 React 应用程序中看不到数据的当前状态

问题描述 投票:0回答:1

我搜索了很多教程,并在谷歌上搜索了几个小时。我找不到任何东西来回答为什么 SignalR 回调看不到我的数据的当前状态,但 React 做得很好。

首先,我的代码(无论如何都是简化版本):

反应组件:

function example() {
    const [data, setData] = useState<DataModel[]>([]);

    useEffect(() => {
        loadSignalR();
        loadData();
    }, []);

    async function loadData() {
        const serverData= await getAllData();
        setData(serverData);
    }

    function addData(addedItem: DataModel) {
        setData([...data, addedItem]);
    }

    function loadSignalR() {
        signalRService.startConnection(`${BASE_PATH}/dataHub`);
        signalRService.onDataAdded(addData);
    }

    return (
        <div className="ps-3" style={{ minWidth: '50vw' }}>
            <h2 className="w-100 text-center">Data</h2>
            
            <DataCarouselContainer
                data={data}
            />
        </div>
    );
}

和信号RService:

const signalRService = {
    connection: null,

    startConnection: hubUrl => {
        signalRService.connection = new HubConnectionBuilder()
            .withUrl(hubUrl)
            .build();

        signalRService.connection
            .start()
            .then(() => signalRService.addToGroup('QT'))
            .then(() => {
                console.log('SignalR connection established.');
            })
            .catch(err => {
                console.error('Error starting SignalR connection:', err);
            });
    },

    onDataAdded: callback => {
        signalRService.connection.on('DataAdded', serverData=> {
            callback(serverData);
        });
    },

    addToGroup: groupName => {
        signalRService.connection.invoke('AddToGroup', groupName).catch(err => {
            console.error('Error adding to group:', err);
        });
    },
};

export default signalRService;

后端工作正常。它发送事件并由前端接收它们。一切似乎都正常,但是当调用 addData 时,它将数据视为空数组。我的屏幕显示它并不是真正空的,因为我可以看到屏幕上列出了 4 个项目。

那么我做错了什么?为什么 SignalR 只将数据状态视为空数组?

好消息/坏消息是,在我的谷歌搜索中,我找到了具有相同问题的其他人的解决方法。如果我创建第二个一次性变量,请说:

const [newData, setNewData] = useState<TaskModel[]>([]);

然后添加一个新的useEffect,例如:


    useEffect(() => {
        setData([...data, ...newData]);
    }, [newData]);

它有效。 newData 成为一次性数据,而 React 将数据视为当前状态。所以在 useEffect 中我可以更新数据并显示它。

问题是,它很混乱,如果我想做更多事件,比如删除数据,我需要添加更多废弃代码和更多 useEffects。它很容易失控,我讨厌这样的想法。我只是希望 SignalR 能够正确查看当前状态,而不必每次数据更改时都创建新连接。

我尝试分离代码。我尝试直接、间接、甚至使用事件数组设置数据。

我尝试使用单个 useEffect 无济于事(创建了无限循环)。

除了一次性代码之外,似乎什么都不起作用。

reactjs signalr
1个回答
0
投票

JavaScript 闭包是您遇到问题的原因。它总是看到一个空数组,因为当您从 SignalR 回调中调用 addData 时,它会记录注册回调时的数据状态。

这是一种更有效的方法来处理该问题,而无需创建第二个状态:

  • 使用功能更新:可以通过利用反应状态更新和功能更新来使用最新状态。
  • 引用和状态组合:使用引用来跟踪当前状态而不需要重新渲染也是有益的。

更新您的组件以使用参考:

function example() {
const [data, setData] = useState<DataModel[]>([]);
const dataRef = useRef<DataModel[]>([]);

useEffect(() => {
    loadSignalR();
    loadData();
}, []);

async function loadData() {
    const serverData = await getAllData();
    setData(serverData);
    dataRef.current = serverData;
}

function addData(addedItem: DataModel) {
    setData(prevData => {
        const updatedData = [...prevData, addedItem];
        dataRef.current = updatedData;
        return updatedData;
    });
}

function loadSignalR() {
    signalRService.startConnection(`${BASE_PATH}/dataHub`);
    signalRService.onDataAdded(addData);
}

return (
    <div className="ps-3" style={{ minWidth: '50vw' }}>
        <h2 className="w-100 text-center">Data</h2>
        
        <DataCarouselContainer data={data} />
    </div>
);}

使用功能更新方法或结合 ref 和 state 可确保您的 SignalR 回调始终看到最新的状态。这种方法应该消除对一次性代码和额外 useEffect 挂钩的需要。

© www.soinside.com 2019 - 2024. All rights reserved.