Comments (12)
This is different from mdx-js/mdx#2444 (comment).
I didn’t even realize MDX supports useMDXComponents
outside of MDXContent
/ _createMdxContent
. I could see both arguments why it should or shouldn’t. Personally I lean towards it shouldn’t, but changing it would be a breaking change.
Docusaurus could replace @mdx-js/react
with a custom import provider, or even with a fallback to @mdx-js/react
if the user really wants to, like Next.js. This avoids the use of hooks completely.
from docusaurus.
I don't see it in the Playground (maybe because it's framework agnostic?
The playground doesn’t use providers (@mdx-js/react
). With that turned on, this behavior happens. Without, it doesn’t.
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));
I assume MDX is injecting some additional code into the classes which cause the problem.
Yes it does!
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 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.
I didn’t even realize MDX supports useMDXComponents outside of MDXContent / _createMdxContent. I could see both arguments why it should or shouldn’t. Personally I lean towards it shouldn’t, but changing it would be a breaking change.
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 <This>
), and for b) overwriting markdown things (so # This
), not for overwriting <div>
. In this case, JSX in an export / expression, the b) example will never happen. But the code is injected anyway.
That is to say, regardless of class components or function components, the provider should not be injected for <div>
.
Only if someone puts <This>
in a function (whether function or class component), that should happen.
And I don’t consider fixing it as a breaking change as it’s the always intended behavior.
Why is the React context API not allowed in classes?
from docusaurus.
Hooks are not allowed in class components, so useMDXComponents/_provideComponents() won' work.
If you choose to use something other than @mdx-js/react
, there could be anything happening in there. It’s more that @mdx-js/react
has a hook (React.useContext(MDXContext)
). Could we read from context, that would work in a class, some other way?
Consumer
was indeed originally used: mdx-js/mdx@07e3a72#diff-b927989ca8df29e648b84decc4a008d4280568465bfec6e72548f1389d111669
from docusaurus.
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.
from docusaurus.
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\" // ...
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
from docusaurus.
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 MDXContext
being exported @wooorm so I thought maybe class support has never been implemented?
https://mdxjs.com/packages/react/
from docusaurus.
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.
from docusaurus.
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.
Agree, that's a niche use case 😅
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.
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 _createMdxContent
" call being involved here.
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);
}
from docusaurus.
I don’t think many people use class components with MDX
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. 😁
from docusaurus.
The playground doesn’t use providers (
@mdx-js/react
). With that turned on, this behavior happens. Without, it doesn’t.
👍
That could be a useful new playground option to add?
That is to say, regardless of class components or function components, the provider should not be injected for
<div>
. Only if someone puts<This>
in a function (whether function or class component), that should happen. And I don’t consider fixing it as a breaking change as it’s the always intended behavior.
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.
Why is the React context API not allowed in classes?
What do you mean?
Hooks are not allowed in class components, so useMDXComponents
/_provideComponents()
won' work.
But context remains supported with static contextType
and this.context
.
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 MDXContext
is not exported atm.
from docusaurus.
The problem with contextType
is that you can only have one context type per class component. (Unless there’s something I don’t know?)
from docusaurus.
Yes, otherwise you can use <MDXContext.Consumer>
😅
from docusaurus.
Related Issues (20)
- how to create code blocks new design HOT 1
- Mermaid not displaying correctly in mdx HOT 2
- Reference link to source path introduce extra ) HOT 1
- Issues with npm run build with custom calendar component HOT 2
- End-of-line CRLF sequence causes TabItem compilation error HOT 4
- Math equations do not work when imported from another file HOT 3
- Unable to import type for `SidebarItemConfig` in a typescript Docusaurus project. HOT 1
- Table of contents should scroll with content HOT 7
- RangeError: Invalid string length when building with a very large number of blogs HOT 7
- Broken link in a-tag not detected HOT 7
- Navbar: Menu Item: Caret / Arrow Is Invisible When Deployed On Azure SWA (using MSAL) HOT 2
- Duplicated whole page when accessing site by your-domain.com/index.html HOT 4
- [Accessibility]: Page looses focus after Search modal gets closed HOT 1
- Please Block the "Bruce's Wiki" at show case since contain the Malicious links HOT 2
- Place screenshots in the themes documentation page in the site HOT 3
- Passing custom props to IdealImage HOT 2
- Spaces are no longer valid in links HOT 4
- Cannot load docs from outside local package root when running as a Yarn workspace HOT 8
- Mermaid diagram shift page when opening a link with anchor HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from docusaurus.