vue3中jsx使用的特殊地方

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

jsx在vue中意味着什么

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

const Btn = <button onClick={() => count.value++}>click{count.value}</button>

相当于

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中

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中

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最常用的场景就是编写函数式组件,基本写法是这样的

const Com = () => <button>click</button>

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

函数式组件的入参

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

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

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

结合ts编写函数式组件

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

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)
 }}/>)

使用方式

<FuncCom v-model:value="value" />

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

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

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

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

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

对于slots类型,没找到方法

至于为什么需要加上

[key: string]: unknown

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

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

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

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

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

特殊的emit特性

假设当我们定义了一个Input组件

export const Input = defineComponent({
 props: {
   value: String,
 },
 emits: ['update:value'],
 setup(props, { emit }: any) {
   return () => <input value={props.value} onChange={(e: any) => {
     emit('update:value', e.target.value)
   }}/>
 },
})

而后编写函数式组件直接返回这个组件(有div或者<></>包裹着也不行)

const InputFunc=()=><Input />

<template>
  <InputFunc
   :value="msg" //设置无效属性值不会透传
   @update:value="handleUpdateValue" //事件监听有效它会被监听
 />
</template>

也就是说当一个函数式组件直接返回另一个组件时,它的emit事件会被透传

以上

原文链接:https://juejin.cn/post/7266108121041616907 作者:成路

(0)
上一篇 2023年8月13日 上午10:37
下一篇 2023年8月13日 上午10:47

相关推荐

发表回复

登录后才能评论