如果我真的必须(比如通过 WebAPI 保存设备连接),我如何在不破坏它的情况下将不可序列化的变量存储在 react - redux 状态中

How do I store a non serialisable variable in a react - redux state without breaking it if I really must (like saving a device connection via WebAPIs)

我几乎在每个 google 搜索结果中都收到声明“不要在您的状态下保存不可序列化的变量” - 但是当我真的应该时会发生什么?

Progect: 我正在为通过串行端口连接的设备S 构建一个应用程序(使用SerialPort WebAPI)。 我希望保存连接实例,因为我在我的所有应用程序中都使用它,老实说,我厌倦了在需要时上下传递实例,而不知道重新呈现数据和显示新数据的反应——这对我来说也很重要.

我完成的步骤:

但是现在我面临着一个大问题:

Error: Invariant failed: A state mutation was detected between dispatches, in the path 'serialport.0.instance.readable'. This may cause incorrect behavior

我最终直接在 state 中编写了连接方法案例,并使用“promise”新变量来处理结果。

// click in a react component 
const handleConnect = () => {
    try {
        if ( dispatch(connect(device)) ) {
            setActiveStep((prevActiveStep) => prevActiveStep + 1)
            return true
        }
    } 
    catch (e) {
        console.error("Device cannot connect: ", e)
    }
}

// In a file that trigges dispatch() to the reduces
const connect = (deviceId) => async (dispatch, getState) => {
    try {
        dispatch({
            type: "serialport/connect",
            payload: deviceId
        })
    } catch(e) {
        console.log(e)
    }
}

// in reducer
const SerialPortDevicesReducer = (state = initialState, action) => {

    switch (action.type) {

        case 'serialport/connect':
            try {
                return {
                    ...state,
                    [action.payload]: {
                        ...state[action.payload],
                        promise: state[action.payload].instance.open({baudRate: 115200})
                    }
                }
            } catch (e) {
                console.error("Cannot run promise inside reducer: ", e)
            }

这是我目前找到的唯一解决方法。这基本上迫使我在 reducer 中处理(可能是一些复杂的)事情,而不仅仅是将数据传递给它。我尝试对写入方法应用相同的方法:

// click in component
const handleExecute = (command) => {
    try {

        dispatch(writeToSP(device1.device, command))
    } catch (e) {
        console.log(e)
    }
}


// In file which trigges the dispatch()
const writeToSP = (deviceId, command = "Z !\n") => async (dispatch) => {
    let startTime = new Date().getTime()
    let encoder = new TextEncoder()
    try {
        dispatch({
            type: "serialport/write", 
            payload: {
                id: deviceId,
                // cmd: encoder.encode(command), 
                // startTime
            }
        })
    } catch (e) {
        console.error("error writing: ", e)
    }
}


// in reducer 
...

    case 'serialport/write':
        try {
            const writer = state[action.payload.id].instance.writable.getWriter()
        } catch (e) {
            console.error("Cannot run promise inside reducer: ", e)
        }

再次出现“错误:不变失败:检测到状态突变...”的错误,我猜测这是它更改了 SerialPort 实例中的其他属性的结果。

拥有像 redux-promise-middleware 这样的包很棒,但在我的状态下似乎是一个对象负责自己的承诺和更改。

我该如何处理这种特殊情况?

很简单:不要把它放到 Redux 中。 Redux 是为数据而生,而不是为任意外部 libraries/dependency 注入而生。

如果该值在初始化后永远不会改变,并且您在 React 之外进行初始化,只需将其放入导出的全局变量中即可。

如果这个值会随着时间变化,你应该使用React的依赖注入机制:Context。这确实是上下文的用途 - 不是共享状态值,而是全局依赖性。