react-scoped-css icon indicating copy to clipboard operation
react-scoped-css copied to clipboard

Dealing with React Fragment

Open fuweichin opened this issue 4 years ago • 6 comments

When using 'babel-plugin-react-scoped-css' with <Fragment>, React gives a warning in DevTools Console:

Warning: Invalid prop data-v-d2ab454f supplied to React.Fragment. React.Fragment can only have key and children props.

The component:

import React, {Component, Fragment} from 'react';

export default class Test extends Component {
  constructor (props) {
    super(props);
    this.state = {};
  }
  render () {
    return <Fragment>
      <div>Part 1</div>
      <div>Part 2</div>
    </Fragment>;
  }
};

fuweichin avatar Aug 11 '20 12:08 fuweichin

Check this out, same issue https://github.com/gaoxiaoliangz/react-scoped-css/issues/2

gaoxiaoliangz avatar Aug 13 '20 06:08 gaoxiaoliangz

Consider bypassing <Fragment> by adding an option like pragmaFragIdentifier to identify it.

Here is a solution:

  1. edit babel-plugin-react-scoped-css/index.js, add the commented code below
      JSXElement(path, stats) {
        if (!this.hasScopedCss || path.node.openingElement.name.type === 'JSXMemberExpression') {
          return
        }
        // let { pragmaFragIdentifier } = stats.opts;
        // if (pragmaFragIdentifier && path.node.openingElement.name.name === pragmaFragIdentifier) {
        //   return
        // }
  1. edit babel run config, add an option pragmaFragIdentifier (just like pragmaFrag for @babel/preset-react)
{
  "plugins": [
    ["babel-plugin-react-scoped-css", {
      "pragmaFragIdentifier": "Fragment"
    }]
  ]
}
  1. Optionally, let option pragmaFragIdentifier default to "Fragment"
    I think may React developers use <Fragment>, there are two issues raised so far. For developers who use custom JSX <Fragment>, they may they may set pragmaFragIdentifier to ""

Sorry to be so verbose, I'm crafting a React project boilerlate for Vue.js-camp co-workers.

fuweichin avatar Aug 14 '20 06:08 fuweichin

Consider a situation like this

const Select = {
  Fragment: () => <div>fragment</div>
}

const App = () => {
  return <Select.Fragment />
}

In this situation Select.Fragment is supposed to receive data-v-* prop but with the implementation above it won't.

gaoxiaoliangz avatar Aug 14 '20 06:08 gaoxiaoliangz

My idea is not to add data-v-* support on React Fragment, but to bypass(not to add data-v-* on) Fragment.

Assuming Fragment JSX can be written in 3 forms:

  • Short syntax <>
  • JSXMemberExpression syntax like <React.Fragment>, <My.React.Fragment>
  • Identifier syntax like <Fragment>, <ReactFragment>

Currently neither "Short syntax" nor "JSXMemberExpression syntax" will trigger the React warning mentioned above, but "Identifier syntax" like <Fragment> will. thus I have to use <> or <React.Fragment> to avoid the warning.

fuweichin avatar Aug 17 '20 03:08 fuweichin

Adding pragmaFragIdentifier config doesn't seem to be a good idea, this job is supposed to be done by the plugin. Maybe it's just enough to just bypass adding data-v-* for <>, <Fragment> and <React.Fragment>. And let users known this behavior i'n the docs until we have a better solution.

Or maybe we can do a simple static analysis on the module to make sure Fragment is actually exported from react.

gaoxiaoliangz avatar Aug 17 '20 08:08 gaoxiaoliangz

Consider a situation like this

const Select = {
  Fragment: () => <div>fragment</div>
}

const App = () => {
  return <Select.Fragment />
}

In this situation Select.Fragment is supposed to receive data-v-* prop but with the implementation above it won't.

Well it still doesn't because the plugin completely ignores any component name with dots in it

LoganDark avatar Dec 12 '21 19:12 LoganDark