Vue3 JSX函数式组件中Ref失效原因及解决方案咨询
Vue3.2 JSX函数式组件内部ref失效问题解析
你遇到的问题:在Vue3.2的JSX函数式组件内部定义的ref无法正常工作,但将ref移到函数外部后就能正常运行,对应代码如下:
// vue3.2 jsx functinal components import { ref } from 'vue' // const count = ref(0) // (2) 这里定义可以正常工作 export default function Counter() { const count = ref(0) // (1) 这里定义无法正常工作 return ( <> <div>count: {count.value}</div> <button onClick={() => { count.value++ }} > add </button> </> ) }
原因分析
Vue的纯函数式组件本质是一个普通函数,每次组件重新渲染时这个函数都会被完整调用一次:
- 当
count = ref(0)写在函数内部(标注(1)处)时,每次渲染都会生成一个全新的ref实例,之前点击按钮修改的状态会被直接丢弃,下一次渲染又回到初始值0,页面自然不会更新。 - 把ref定义在函数外部(标注(2)处)时,这个ref实例只会被创建一次,属于模块级的全局变量,所有渲染周期共享同一个状态,修改后状态能被保留,页面也会正常响应更新。
可行解决方案
- 用
<script setup>语法写JSX组件:这是Vue3推荐的组件写法,内部定义的ref会被自动绑定为组件的响应式状态,不会每次渲染重建。示例:
import { ref } from 'vue' export default defineComponent({ setup() { const count = ref(0) return () => ( <> <div>count: {count.value}</div> <button onClick={() => count.value++}>add</button> </> ) } })
更简洁的<script setup>+JSX写法:
<script setup lang="jsx"> import { ref } from 'vue' const count = ref(0) const render = () => ( <> <div>count: {count.value}</div> <button onClick={() => count.value++}>add</button> </> ) </script>
- 通过闭包保留ref实例:如果一定要用纯函数式组件,可以用立即执行函数创建闭包,让ref被组件函数共享,避免每次渲染重建:
import { ref } from 'vue' export default (() => { const count = ref(0) return function Counter() { return ( <> <div>count: {count.value}</div> <button onClick={() => count.value++}>add</button> </> ) } })()
- 使用组件状态属性维护:通过组件的props或上下文传递状态(比如配合
reactive),但这种方式繁琐,仅适合特殊场景,不推荐作为常规方案。
内容的提问来源于stack exchange,提问作者MurphyChen
相关产品推荐
相关产品推荐

