• home > webfront > ECMAS > vue >

    JSX与Vue Template(SFC):React比Vue2.x更适合集成TS,Vue3+TSX境况几何

    Author:zhoulujun Date:

    既然升级vue3的主要目的是为了更好低与TS配合,JSX上了后。发现还是有很多问题需要注意。虽然觉得react很好,但是项目选择vue3,还是得咬牙学。

    在看 

    感慨蛮多,文章的精华部分如下:


    父组件

    1. TSX 要用 defineComponent 包裹,并且只使用 setup(没有 data、methods、computed 等一级声明),返回值要是一个 render function,里面采用 JSX 的写法;

    2. TSX(defineComponent) 中 components、props、emits 等的声明是省不了的,props 的声明我们看下文 Child 的实现;

    3. @click 在 TSX 中要变为 onClick,自定义 emit 也要由 @child-click 变为 onChildClick。不过这里要注意,正如“短篇”中提到的,如果用了 TSX,像 onClick 这种可能引起无效重复 render 的问题,就需要使用者自己解决了;

      注:如果在 template 中同时传入 @childClick 和 :onChildClick 会发生什么呢?

      答案是:不管传入顺序如何,:onChildClick 都会覆盖掉 @childClick,有兴趣的同学可以验证一下。所以在 template 中,事件还是老老实实的用 @ 的好。

    4. TSX 中的 ref 对象还是需要使用 .value 结尾,有点麻烦,但是编辑器会自动补全;

    5. 如果有多个slots,TSX 要像例子中一样,通过一个对象传入子组件。对象的 key 为 slot 的名字,value 为要传入的组件;

    特别注意的就是 emits 和 slots 的特殊处理。另外,上例当中还存在一个比较大的问题,即 onChildClick 实际上会被编译器提示 TS 校验错误,但代码又是可运行的。要想解决这个问题,只能要求子组件不声明 emits,全部用 props.onXXX 代替,即放弃使用 emits(感觉不太合适)。这点现在是最难受的,笔者还没有想到一个好的解决方案。

    vue3 TSX写法示范-父组件


    子组件

    1. 注意两者 emits 声明的不同,SFC 中参考官网的例子(仅限类型的 props/emit 声明),TSX 中 Emit 的声明一定要是 type 格式而不能是 interface,这是由 FunctionalComponent 内部泛型处理逻辑决定的;

    2. TSX 中可以使用解构赋值,这是一个组件二次封装的场景下很常用的一个语法;

    3. slots 在 TSX 中以函数的形式调用,注意例子中的容错写法,防止没有 slot 传入时的报错;综上,在 Functional Componet 的场景下,选择 TSX 是个不错的决定。如果用 defineComponet 的方式实现 Child 应该是什么样呢?也顺便解答一下上面留下的一个疑问,关于 props 声明的问题。

    vue3 TSX写法示范-子组件


    Child.tsx 的普通写法

    import { CSSProperties, defineComponent, PropType } from "vue";
    
    interface Props {
      count: number;
      style: CSSProperties;
    }
    export default defineComponent({
      props: {
        style: {
          type: Object as PropType<Props["style"]>,
          default: undefined,
        },
        count: {
          type: Number as PropType<Props["count"]>,
          default: undefined,
        },
      },
      emits: ["childClick"],
      setup(props, ctx) {
        const { slots, emit } = ctx;
        return () => (
          <div style={props.style}>
            <h1>This is Child</h1>
    
            {slots?.header && slots.header()}
            <button onClick={() => emit("childClick")}>Child Count++</button>
            <p>Child count is: {props.count}</p>
    
            {slots?.default && slots.default()}
            <p>Props' keys are: {Object.keys(props).join(", ")}</p>
          </div>
        );
      },
    });



    转载本站文章《JSX与Vue Template(SFC):React比Vue2.x更适合集成TS,Vue3+TSX境况几何》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8707.html