【问题标题】:State variable hook not working with useEffect callback状态变量钩子不适用于 useEffect 回调
【发布时间】:2020-09-21 20:46:15
【问题描述】:

尝试在 react 功能组件中建立 websocket 连接,并使用钩子更新状态变量,如下所示 [Ref 1]:

export default function foo() {
    const [ arr, setArr ] = useState([])
    ws = useRef(null)

    useEffect( () => {
        ws.current = new Websocket('ws://example.com:1234')
        ws.current.onmessage = (m) => {
            setArr([...arr, m])
        })
    }, []) // Runs once at mount
}

arr 的状态未被保留。它被覆盖了。

注意我也尝试将arr 传递给效果,就像这样,但这导致了无限循环。 [参考 2]。随着 arr 的更新,效果被调用...

        })
    }, [arr])
}

举个更具体的例子,取三个 websocket 消息:

['a']
['b']
['c']

更新后每条消息的预期 arr

['a']
['a', 'b']
['a', 'b', 'c']

结果:

['a']
['b']
['c']

为什么arr 不与回调中的setArr 挂钩存储?为什么是空数组?

参考文献

  1. WebSockets with functional components
  2. https://github.com/facebook/react/issues/14066

【问题讨论】:

标签: javascript reactjs websocket react-hooks state


【解决方案1】:

你有

useEffect( () => {
    ws.current = new Websocket('ws://example.com:1234')
    ws.current.onmessage = (m) => {
        setArr([...arr, m])
    })
}, []) // Runs once at mount

确实,那里的效果挂钩在挂载时运行一次 - 这就是问题所在。当它运行时,附加的事件侦听器在触发时运行此行:

setArr([...arr, m])

使用该处理程序范围内的arr 的值。由于处理程序仅附加一次,因此在挂载时,arr 的值始终相同;初始状态,空数组。

改用回调:

setArr(arr => [...arr, m])

我还建议将wsconst 一起声明,以避免意外创建全局变量(并且可能将其称为wsRef 而不是ws,因此您不要混淆套接字的引用):

const wsRef = useRef(null)

【讨论】:

    【解决方案2】:

    您可以尝试使用数组的先前状态:

    ws.current.onmessage = (m) => {
       setArr(prevState => [...prevState, m])
    }
    

    对于setState,有两种处理变化的方法,第一种是给一个值作为参数,第二种是传递一个回调函数强>。它被称为更新函数,它提供状态的先前值。进一步了解setState here

    【讨论】:

    • prevState 来自哪里?
    • @kmiklas 刚刚更新了我的解决方案来回答你的问题,希望能澄清一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2020-05-23
    • 2021-10-24
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多