What——发生了什么
今天遭遇了一个问题,在函数A内给函数A外声明的变量a赋值,函数B中访问变量a,却为 undefined
,简化代码如下:
const Demo = () => {
const [message, setMessage] = useState<string>('')
let target: EventSource
const functionA = () => {
target = new EventSource('#href#')
console.log(target) // EventSource Object
target.onmessage = (event) => {
setMessage(event.data)
}
}
const functionB = () => {
console.log(target) // undefined
target.close() // 无效
}
return (
<div>{message}</div>
<button @click={functionA}>A</button>
<button @click={functionB}>B</button>
)
}
Why——为什么
React 组件的渲染是声明式的,每次渲染都会生成新的 JSX 输出,并根据新的输出更新 DOM。这意味着在每次渲染时,函数组件都会被重新执行,从而创建新的局部变量。
说人话:setMessage造成了组件渲染,渲染会重置局部普通变量,没错,
target
被重置了
How——怎么解决
useRef
持久化
useRef
提供了一种方式来创建一个在组件的整个生命周期内持续存在的对象。这个对象的 .current
属性可以用于存储任意可变值,并且 React 不会因为组件的重新渲染而重置这个对象。这就意味着你可以在组件的多个渲染周期之间持久化某些数据,而不会丢失这些数据。
挺浅显易懂的,就不说人话了
优化后代码如下
const Demo = () => {
const [message, setMessage] = useState<string>('')
const targetRef = useRef<EventSource>()
const functionA = () => {
targetRef.current = new EventSource('#href#')
console.log(target) // EventSource Object
targetRef.current.onmessage = (event) => {
setMessage(event.data)
}
}
const functionB = () => {
console.log(targetRef.current) // EventSource Object
targetRef.current.close()
}
return (
<div>{message}</div>
<button @click={functionA}>A</button>
<button @click={functionB}>B</button>
)
}
评论区