归纳总结一下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" /> //有效的
以上