vue3中jsx使用的特殊地方

归纳总结一下vue3中使用jsx特殊的地方,就不对jsx的基本语法做介绍了

jsx在vue中意味着什么

jsx元素在vue中相当于一个render函数,也就是说

ts 复制代码
const Btn = <button onClick={() => count.value++}>click{count.value}</button>

相当于

ts 复制代码
const Btn2 = h('button', {
 onClick: () => count.value++,
}, `click${count.value}`)

关于vue和react的render

仅针对于现在vue的setup写法和react hooks的写法

vue 的组件可以分成setup阶段和render阶段,而react相当于只有render阶段,两者在数据变更从而视图需要更新时所做的事情其实是类似的,都是重新执行render函数,创建新的vnode

在vue中

tsx 复制代码
export const Com = defineComponent({
  setup: () => {
    const count = ref(1)

    const interval = setInterval(() => {
      count.value++
    }, 1000)

    onBeforeUnmount(() => {
      clearInterval(interval)
    })

    return {
      count,
    }
  },
  render: (props: any) => {
    console.log('render')// 每次render都会执行
    return <p>{props.count}</p>
  },
})

在react中

tsx 复制代码
function App() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const interval = setInterval(() => {
      setCount(count + 1)
    }, 1000)

    return () => clearInterval(interval)
  })

  console.log('render')// 每次render都会执行

  return (
    <p>{count}</p>
  )
}

react中每次执行函数得到一个新的VNode,并通过hooks来保证同一个组件前后数据的一致和一些副作用的设置和清除。而vue中同样是每次执行render函数得到一个新的VNode,不同的是,vue的数据和副作用的设置是放在setup阶段的,仅会执行一次。

因此,在vue的render函数中,不要编写含有副作用的代码,这大概率会引发bug,因为vue并没有提供react hooks类似的api去做一些副作用的设置和清除。

使用jsx编写函数式组件

使用jsx最常用的场景就是编写函数式组件,基本写法是这样的

tsx 复制代码
const Com = () => <button>click</button>

相当于一个只有render函数的组件,它的数据和副作用都从外部来,自身只负责创建VNode渲染

函数式组件的入参

除了可以使用上下文的数据进行渲染外,函数式组件还可以接受入参,它的参数是这样的

tsx 复制代码
export const FuncCom = (props: any, { attrs, slots, emit }: any) => <div>{{ ...slots }}</div>

这里的props和attrs是一样的,emit也就是vue的emit,slots也就是vue的slots

结合ts编写函数式组件

通过给props添加类型声明,可以给函数式组件更好的类型提示,例如

tsx 复制代码
export const FuncCom = (props: {
 value: string
 'onUpdate:value'?: (val: string) => void
 [key: string]: unknown
}) =>
 (<input type="text" value={props.value} onChange={(e) => {
   props['onUpdate:value']?.((e.target as any).value)
 }}/>)

使用方式

html 复制代码
<FuncCom v-model:value="value" />

对于普通的props类型都可以通过 value:string 这样的类型添加在props里面;

对于事件类型,vue3可以通过将对应事件改成on开头的props达到类型提示,如

tsx 复制代码
export const FuncCom = (props: {
  onEvent?: (e: Event) => void
  [key: string]: unknown
}) => <></>

这样就生成了一个event的事件类型提示,既可以传递onEvent,也可以传递@event,看起来就跟正常的组件一样

例子里使用 props'onUpdate:value'?.((e.target as any).value) 去传递事件,这在大多数情况下是可行的,但如果你给函数式组件添加了多个事件监听器,则还是建议采用emit的形式发送事件

对于slots类型,没找到方法

至于为什么需要加上

ts 复制代码
[key: string]: unknown

则是因为函数式可能需要传递一些组件通用可传递的属性,例如class,style,title等,免得传递这些属性时报类型错误

需要提醒的是,props仅限于类型声明,它不是真正的props

例如组件声明一个props为showTitle,则在template中,我们不论写showTitle还是show-title都是可行的,因为vue会对其进行处理

但是对于函数式组件声明的showTitle,则只能传递showTitle,而不能是show-title

tsx 复制代码
export const FuncCom = (props: {
 showTitle: string
}) => <span>{props.showTitle}</span>
html 复制代码
<FuncCom show-title="666" /> // 无效的
<FuncCom showTitle="666" /> //有效的

以上

相关推荐
卸任3 小时前
Vibe coding工具使用心得
前端·ai编程
brien94 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance4 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M4 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写4 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李4 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易4 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马5 小时前
前沿视界
前端
kyriewen5 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易5 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员