Skip to content

Generated JSX should not define component on rerender #2029

Closed
@remcohaszing

Description

@remcohaszing

Initial checklist

Affected packages and versions

^2.0.0-rc.2 (#1810)

Link to runnable example

No response

Steps to reproduce

Run the following script:

import { compile } from '@mdx-js/mdx';

const { value } = await compile('hello', { jsx:true })

console.log(value)

The jsx option is there for readability of the output. The issue applies if it’s either true or false.

Expected behavior

The output doesn’t define a component inside a component. This is a React anti-pattern, because it causes unnecessary rerenders

The following Google search yields some articles that explain why this is a bad idea in React: https://www.google.com/search?q=react+create+component+inside+component. Example article: https://dev.to/borasvm/react-create-component-inside-a-component-456b. The same principles apply to Preact.

Earlier the output was ok:

/*@jsxRuntime automatic @jsxImportSource react*/
function MDXContent(props = {}) {
  const _components = Object.assign({
    p: "p"
  }, props.components), {wrapper: MDXLayout} = _components;
  const _content = <><_components.p>{"hello"}</_components.p></>;
  return MDXLayout ? <MDXLayout {...props}>{_content}</MDXLayout> : _content;
}
export default MDXContent;

Alternative output that’s also ok for React/Preact, although I recall it’s troublesome for some frameworks:

/*@jsxRuntime automatic @jsxImportSource react*/
import { Fragment as _Fragment } from 'react/jsx-runtime.js'
function MDXContent(props = {}) {
  const _components = Object.assign({
    p: "p"
  }, props.components), {wrapper: MDXLayout = _Fragment} = _components;
  return <MDXLayout><_components.p>{"hello"}</_components.p></MDXLayout>;
}
export default MDXContent;

Actual behavior

The output does define a component inside a component, which causes unnecessary rerenders.

/*@jsxRuntime automatic @jsxImportSource react*/
function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || ({});
  return MDXLayout ? <MDXLayout {...props}><_createMdxContent /></MDXLayout> : _createMdxContent();
  function _createMdxContent() {
    const _components = Object.assign({
      p: "p"
    }, props.components);
    return <_components.p>{"hello"}</_components.p>;
  }
}
export default MDXContent;

Runtime

Node v16

Package manager

npm v8

OS

Linux

Build and bundle tools

Other (please specify in steps to reproduce)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions