-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invalid hook call when using react class component in MDX #9905
Comments
Hi, I think this is an MDX issue (or maybe, design decision). The issue can be reproduced without Docusaurus: // webpack.config.js
module.exports = {
mode: "development",
entry: "./index.tsx",
output: {
filename: "my-first-webpack.bundle.js",
},
module: {
rules: [
{
test: /\.mdx$/,
use: {
loader: "@mdx-js/loader",
options: {
providerImportSource: "@mdx-js/react",
},
},
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
}; {/* doc.mdx */}
import React from 'react'
export class Test extends React.Component {
render() {
return (<div>Title</div>);
}
}
<Test /> // index.tsx
import React from "react";
import ReactDOM from "react-dom";
import Doc from "./doc.mdx";
ReactDOM.render(<Doc />, document.getElementById("root")); The output produced contains the following: render() {
const _components = {
div: "div",
...(0,_mdx_js_react__WEBPACK_IMPORTED_MODULE_2__.useMDXComponents)()
};
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxDEV)(_components.div, {
children: \"Title\"
// ... This is expected output per https://mdxjs.com/guides/injecting-components/. Please reach out to them to see if they want to support this. |
Yes, using hooks in a class component is not going to work 😅 How do you get this output? This is surprising because the MDX playground doesn't give me this |
Wondering what could be the compiled output of a React class component for MDX. Particularly, if the user uses components provided by context: import React from 'react'
export class Test extends React.Component {
render() {
return <SomeComponent/>
}
} Should the output be the following? import React from 'react'
class Test extends React.Component {
static contextType = MDXContext;
render() {
const {SomeComponent} = this.context;
return <SomeComponent/>
}
} I don't see the |
I don’t think many people use class components with MDX 😅 Or at least maybe they do but don’t have issues with it? Also, not everyone uses context-based providers, and together, expect components to be injected from them in class methods. I think the MDX issue here is explained here: mdx-js/mdx#2444 (comment), a solution is being thought up here: mdx-js/mdx#2445. MDX also isn’t tied to React. So if the class story improves, we have to be careful to not mess with classes in other frameworks. |
Agree, that's a niche use case 😅
I'm not sure @remcohaszing PR will fix this. I don't see it in the Playground (maybe because it's framework agnostic?) but I see this in the dev tools, and there's no "conditional import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
import {useMDXComponents as _provideComponents} from "@mdx-js/react";
import React from 'react';
export class Test extends React.Component {
render() {
const _components = {
div: "div",
..._provideComponents() // ❌ BAD
};
return _jsx(_components.div, {
children: "Title"
});
}
} We are simply calling a hook in a class component, which doesn't work. Repro: https://stackblitz.com/edit/github-fq9usu?file=docs%2Fintro.md MDX source: ---
sidebar_position: 1
---
# Tutorial Intro
import React from 'react'
export class Test extends React.Component {
render() {
return (<div>Title</div>);
}
}
<Test />
Full module source code seen in DevTools: import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
import {useMDXComponents as _provideComponents} from "@mdx-js/react";
import React from 'react';
export class Test extends React.Component {
render() {
const _components = {
div: "div",
..._provideComponents()
};
return _jsx(_components.div, {
children: "Title"
});
}
}
export const toc = [];
function _createMdxContent(props) {
const _components = {
h1: "h1",
..._provideComponents(),
...props.components
};
return _jsxs(_Fragment, {
children: [_jsx(_components.h1, {
id: "tutorial-intro",
children: "Tutorial Intro"
}), "\n", "\n", "\n", _jsx(Test, {})]
});
}
export default function MDXContent(props = {}) {
const {wrapper: MDXLayout} = {
..._provideComponents(),
...props.components
};
return MDXLayout ? _jsx(MDXLayout, {
...props,
children: _jsx(_createMdxContent, {
...props
})
}) : _createMdxContent(props);
} |
https://github.com/search?q=%22export+class%22+React.Component+language%3Amdx&type=code There are some false-positives (code snippets instead of components declared in MDX) in the result but it gives a high level insight data it is used here and there. But there are really not many results I personally find it interesting that things work if you move the react class components into a dedicated file and import it. One would assume that the callstack and execution flows stay the same on rendering. Maybe this can give some hints on supporting class components within MDX? I assume MDX is injecting some additional code into the classes which cause the problem. If class components cannot be supported (anymore) it might be worth to emit some user/dev friendly warnings/errors (configurable?). Even though I raised the issue I'm also fine with not having support for class components within MDX. I refactored my code to pull out the more complex components and things are working fine for me now. 😁 |
This is different from mdx-js/mdx#2444 (comment). I didn’t even realize MDX supports Docusaurus could replace |
The playground doesn’t use providers ( import { compile } from "@mdx-js/mdx";
const document = `
import React from 'react'
export class Test extends React.Component {
render() {
return (<div>Title</div>);
}
}
<Test />`;
const result = await compile(document, {
providerImportSource: "@mdx-js/react",
});
console.log(String(result));
Yes it does!
I checked the first 15, and 13 were code blocks. The only 2 components are https://github.com/trytouca/trytouca/blob/0b16f242f5216fe3b49bb3248558e4b1a358308c/docs/docs/sdk/differences.mdx#L8 and https://github.com/ehsanghaffar/touca-core/blob/5ae23339a26813f1c3c8a95415b5c747529e664d/docs/docs/sdk/Readme.mdx#L6. So it seems like very little class components.
The behavior is intentional. People want to inject components into MDX files. That also applies to components in components and components defined in MDX. However, the component injection is for a) undefined components (so That is to say, regardless of class components or function components, the provider should not be injected for Why is the React context API not allowed in classes? |
👍 That could be a useful new playground option to add?
That doesn't seem to be a breaking change for me either 🤔 This looks like a regular bug fix because anyway, atm a simple class component doesn't even work 😅 I don't see how you can break it more.
What do you mean? Hooks are not allowed in class components, so But context remains supported with export class Test extends React.Component {
render() {
return <div><This/></div>
}
} should probably be compiled as: import React from "react";
import {MDXContext} from "@mdx-js/mdx";
export class Test extends React.Component {
static contextType = MDXContext;
render() {
const _components = {
div: "div",
...this.context,
};
return _jsx(_components.div, {
children: _jsx(_components.This),
});
}
} But |
The problem with |
Yes, otherwise you can use |
If you choose to use something other than
|
Closes GH-2449. Related-to: facebook/docusaurus#9905.
Have you read the Contributing Guidelines on issues?
Prerequisites
npm run clear
oryarn clear
command.rm -rf node_modules yarn.lock package-lock.json
and re-installing packages.Description
When you try to declare react components using
React.Component
in MDX files you end up with anInvalid hook call.
error.Reproducible demo
No response
Steps to reproduce
docs/tutorial-basics/markdown-features.mdx
Expected behavior
It should be possible declare React class components in MDX files without errors.
Actual behavior
The page crashes with:
Moving the same class/code into a separate
.tsx
undersrc/
and importing it into the MDX works.Your environment
Self-service
The text was updated successfully, but these errors were encountered: