注入组件
¥Injecting components
本指南展示了如何在 MDX 运行时将任意组件注入到 MDX 中。 它展示了我们的提供商(@mdx-js/react
、@mdx-js/preact
)使用的底层功能和 Next.js 支持的 mdx-components.tsx
文件如何工作,以及你如何自己利用该功能。
¥This guide shows how to inject arbitrary components into MDX when it runs. It shows how the underlying features used by our providers (@mdx-js/react
, @mdx-js/preact
) and the mdx-components.tsx
file supported by Next.js work, and how you can take advantage of that functionality yourself.
在许多情况下,你不需要这样做,因为你可以将组件传递给 MDX:
¥In many cases you do not need this, as you can pass components to MDX:
# Hello *<Planet />*
你可以传递 Planet
并说出使用的组件来代替 h1
:
¥You can pass Planet
and say a component used instead of the h1
:
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(
<Example
components={{
Planet() {
return 'Pluto'
},
h1(properties) {
return <h2 {...properties} />
}
}}
/>
)
(alias) function Example(props: MDXProps): Element
import Example
An function component which renders the MDX content using JSX.
- @param props This value is be available as the named variable
props
inside the MDX component. - @returns A JSX element. The meaning of this may depend on the project configuration. I.e. it could be a React, Preact, or Vuex element.
var console: Console
(method) Console.log(...data: any[]): void
(alias) function Example(props: MDXProps): Element
import Example
An function component which renders the MDX content using JSX.
- @param props This value is be available as the named variable
props
inside the MDX component. - @returns A JSX element. The meaning of this may depend on the project configuration. I.e. it could be a React, Preact, or Vuex element.
(property) MDXProps.components?: MDXComponents
This prop may be used to customize how certain components are rendered.
(method) Planet(): string
(property) h1?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(parameter) properties: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
(property) JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
(parameter) properties: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
当你发现自己经常传递 components
属性时,你可能需要考虑替代方案。你可能会寻求我们基于上下文的提供程序(@mdx-js/react
、@mdx-js/preact
),但上下文具有性能缺点,并且上下文并不总是有效(例如在 RSC 中)。
¥When you find yourself passing that components
prop around a lot, you might want to look at an alternative. You might reach for our context based providers (@mdx-js/react
, @mdx-js/preact
), but context has performance downsides and context doesn’t always work (such as in RSC).
但首先,组件传递是如何工作的?可以通过查看 MDX 为上述 example.mdx
生成的代码来说明这一点。这是一个差异,显示了示例通常编译的内容以及传递 providerImportSource: 'xxx'
时发生的变化:
¥But first, how does component passing work? That can be illustrated by looking at the code generated by MDX for the above example.mdx
. Here is a diff that shows what the example normally compiles to and what changes when providerImportSource: 'xxx'
is passed:
@@ -1,7 +1,13 @@
import {jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
+import {useMDXComponents as _provideComponents} from 'xxx'
function _createMdxContent(props) {
- const _components = {em: 'em', h1: 'h1', ...props.components}
+ const _components = {
+ em: 'em',
+ h1: 'h1',
+ ..._provideComponents(),
+ ...props.components
+ }
const {Planet} = _components
if (!Planet) _missingMdxReference('Planet', true)
return _jsxs(_components.h1, {
@@ -10,7 +16,7 @@ function _createMdxContent(props) {
}
export default function MDXContent(props = {}) {
- const {wrapper: MDXLayout} = props.components || {}
+ const {wrapper: MDXLayout} = {..._provideComponents(), ...props.components}
return MDXLayout
? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {...props})})
: _createMdxContent(props)
请注意,组件具有默认值(例如 h1
将使用 'h1'
),并且组件取自 props.components
。所改变的是添加了对 _provideComponents
的调用,它指的是我们指定的模块 (xxx
) 的 useMDXComponents
导出。
¥Observe that components have defaults (such as that h1
will use 'h1'
) and that components are taken from props.components
. What changes is an added call to _provideComponents
, which refers to an useMDXComponents
export from the module we specified (xxx
).
我们可以使用这个接口从文件中注入组件。在该文件中,我们需要一个返回组件的 useMDXComponents
函数。
¥We can use this interface to inject components from a file. In that file, we need a useMDXComponents
function that returns our components.
/**
* @import {MDXComponents} from 'mdx/types.js'
*/
/** @returns {MDXComponents} */
export function useMDXComponents() {
return {
Planet() {
return 'Pluto'
},
h1(properties) {
return <h2 {...properties} />
}
}
}
function useMDXComponents(): MDXComponents
- @returns
(method) Planet(): string
(property) h1?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(parameter) properties: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
(property) JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
(parameter) properties: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
现在将文件路径或 URL 作为 providerImportSource
传递到该文件,例如使用 import.meta.resolve('./mdx-components.js')
:
¥And now passing a file path or URL to that file as providerImportSource
, such as with import.meta.resolve('./mdx-components.js')
:
@@ -1,5 +1,5 @@
import {jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
-import {useMDXComponents as _provideComponents} from 'xxx'
+import {useMDXComponents as _provideComponents} from 'file:///Users/tilde/…/mdx-components.js'
现在我们本地定义的组件将在所有 MDX 文件中使用!
¥Now our locally defined components will be used in all MDX files!