首页 > 解决方案 > Vue: can't use render props with TSX

问题描述

In my setup jsx written inside vue component works correctly, then I migrate project on TS and use vue-class-component.

The only thing which works with tsx for me is the following (as in example in repo)

import Vue from 'vue'
import { Component } from 'vue-property-decorator'

@Component
export default class TSXTest extends Vue {
  render(h) {
    return <h1>It works</h1>
  }
}

notice h here - without it - it doesn't work, but should

I have a component which can accept render props. Looks like this:

 // this is js component, so works even without `h` added manually 
 render() {
    return (
      <td>
        {this.$props.render
          ? this.$props.render(this)
          : this.defaultRender(this)}
      </td>
    )
  }

In defaultRender some other jsx. And default works fine. But when I try to pass function with jsx, it doesn't work (in TSX, for common vue js based component it works perfect).

I used to have this jsx written inside my created hook. Like this:

created() {
    this.columns = [
      {
        field: 'fieldWithCustomRenderFn',
        label: 'Some name',
        renderCell: ({ row }) => (
          <div onClick={() => this.someHandler(row)}>
            {row.someData}
          </div>
        )
      }
    ]
}

Notice that I don't have to pass h here somehow. It works in JS - but doesn't work in TSX. Have no idea why...

When it's transpiled it looks like this:

renderCell: function renderCell(_a) {
        var row = _a.row
        return h('a', {
          on: {
            'click': function click(e) {
              _this.someHandler(row)
            }
          }
        }, [row.someData])
      }

Indeed, jsx is transformed, but h is undefined here. I saw transpiled code from js (which works) and the key difference as for me is that line:

var h = this.$createElement;

inside created() function. I don't see this line in transpiled code for my tsx component. What I do wrong here?

Here is my .babelrc (I use babel 6)

  "presets": [
    ["env", {
      "modules": "commonjs",
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 11"]
      }
    }],
    "stage-2"
  ],
  "plugins": [
    "syntax-dynamic-import",
    "transform-vue-jsx",
    "transform-runtime"
  ],

And webpack rules

      {
        test: /\.ts$/,
        loader: 'ts-loader',
        exclude: /node_modules/,
        options: {
          appendTsSuffixTo: [/\.vue$/],
          transpileOnly: true
        }
      },
      {
        test: /\.tsx$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
          },
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true
            }
          }
        ]
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: file => (
          /node_modules/.test(file) &&
          !/\.vue\.js/.test(file)
        )
      },

标签: typescriptvue.jsvuejs2tsxvue-class-components

解决方案


That looks like a known issue with babel-plugin-transform-vue-jsx. I solved this just by adding this string manually inside my function with jsx:

const h = this.$createElement;

And it works as it should in terms that it compiles and works fine. But of course it's just a crutch.


推荐阅读