Skip to navigation

注入组件

本指南展示了如何在 MDX 运行时将任意组件注入到 MDX 中。 它展示了我们的提供商(@mdx-js/react@mdx-js/preact)使用的底层功能和 Next.js 支持的 mdx-components.tsx 文件如何工作,以及你如何自己利用该功能。

在许多情况下,你不需要这样做,因为你可以将组件传递给 MDX:

example.mdx
# Hello *<Planet />*

你可以传递 Planet 并说出使用的组件来代替 h1

example.jsx
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

<Example
  components={{
    Planet() {
      return 'Pluto'
    },
    h1(props) {
      return <h2 {...props} />
    }
  }}
/>

当你发现自己经常传递 components 属性时,你可能需要考虑替代方案。 你可能会寻求我们基于上下文的提供程序(@mdx-js/react@mdx-js/preact),但上下文具有性能缺点,并且上下文并不总是有效(例如在 RSC 中)。

但首先,组件传递是如何工作的? 可以通过查看 MDX 为上述 example.mdx 生成的代码来说明这一点。 这是一个差异,显示了示例通常编译的内容以及传递 providerImportSource: 'xxx' 时发生的变化:

Diff
@@ -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 导出。

我们可以使用这个接口从文件中注入组件。 在该文件中,我们需要一个返回组件的 useMDXComponents 函数。

mdx-components.js
/** @returns {import('mdx/types.js').MDXComponents} */
export function useMDXComponents() {
  return {
    Planet() {
      return 'Pluto'
    },
    h1(props) {
      return <h2 {...props} />
    }
  }
}

现在将文件路径或 URL 作为 providerImportSource 传递到该文件,例如使用 import.meta.resolve('./mdx-components.js')

Diff
@@ -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 文件中使用!

MDX 中文网 - 粤ICP备13048890号