Skip to navigation

使用 MDX

¥Using MDX

本文介绍如何在项目中使用 MDX 文件。它展示了如何传递 props 以及如何导入、定义或传递组件。 请参阅 § 入门 了解如何将 MDX 集成到你的项目中。要了解 MDX 格式的工作原理,我们建议你从 § 什么是 MDX 开始。

¥This article explains how to use MDX files in your project. It shows how you can pass props and how to import, define, or pass components. See § Getting started for how to integrate MDX into your project. To understand how the MDX format works, we recommend that you start with § What is MDX.

内容

¥Contents

MDX 的工作原理

¥How MDX works

集成将 MDX 语法编译为 JavaScript。假设我们有一个 MDX 文档 example.mdx

¥An integration compiles MDX syntax to JavaScript. Say we have an MDX document, example.mdx:

input.mdx
export function Thing() {
  return <>World</>
}

# Hello <Thing />

大致变成了下面的 JavaScript。以下内容可能有助于形成心理模型:

¥That’s roughly turned into the following JavaScript. The below might help to form a mental model:

output-outline.jsx
/* @jsxRuntime automatic */
/* @jsxImportSource react */

export function Thing() {
  return <>World</>
}

export default function MDXContent() {
  return <h1>Hello <Thing /></h1>
}
function Thing(): JSX.Element
function MDXContent(): JSX.Element
(property) JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
function Thing(): JSX.Element
(property) JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>

一些观察结果:

¥Some observations:

  • 输出是序列化的 JavaScript,仍需要评估

    ¥The output is serialized JavaScript that still needs to be evaluated

  • 注入注释来配置 JSX 的处理方式

    ¥A comment is injected to configure how JSX is handled

  • 这是一个包含导入/导出的完整文件

    ¥It’s a complete file with import/exports

  • 导出组件 (MDXContent)

    ¥A component (MDXContent) is exported

实际输出是:

¥The actual output is:

output-actual.js
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'

export function Thing() {
  return _jsx(_Fragment, {children: 'World'})
}

function _createMdxContent(props) {
  const _components = {h1: 'h1', ...props.components}
  return _jsxs(_components.h1, {children: ['Hello ', _jsx(Thing, {})]})
}

export default function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || {}
  return MDXLayout
    ? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {...props})})
    : _createMdxContent(props)
}
(alias) const Fragment: React.ExoticComponent<{
    children?: React.ReactNode | undefined;
}>
export Fragment

Lets you group elements without a wrapper node.

  • @see {@link https://react.dev/reference/react/Fragment React Docs}
  • @example
    import { Fragment } from 'react';
    
    <Fragment>
      <td>Hello</td>
      <td>World</td>
    </Fragment>
    
  • @example
    // Using the <></> shorthand syntax:
    
    <>
      <td>Hello</td>
      <td>World</td>
    </>
    
(alias) const _Fragment: React.ExoticComponent<{
    children?: React.ReactNode | undefined;
}>
import _Fragment

Lets you group elements without a wrapper node.

  • @see {@link https://react.dev/reference/react/Fragment React Docs}
  • @example
    import { Fragment } from 'react';
    
    <Fragment>
      <td>Hello</td>
      <td>World</td>
    </Fragment>
    
  • @example
    // Using the <></> shorthand syntax:
    
    <>
      <td>Hello</td>
      <td>World</td>
    </>
    
function jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) function _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) function _jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsxs

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function Thing(): React.ReactElement<any, string | React.JSXElementConstructor<any>>
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

(alias) const _Fragment: React.ExoticComponent<{
    children?: React.ReactNode | undefined;
}>
import _Fragment

Lets you group elements without a wrapper node.

  • @see {@link https://react.dev/reference/react/Fragment React Docs}
  • @example
    import { Fragment } from 'react';
    
    <Fragment>
      <td>Hello</td>
      <td>World</td>
    </Fragment>
    
  • @example
    // Using the <></> shorthand syntax:
    
    <>
      <td>Hello</td>
      <td>World</td>
    </>
    
(property) children: string
function _createMdxContent(props: any): React.ReactElement<any, string | React.JSXElementConstructor<any>>
(parameter) props: any
const _components: any
(property) h1: string
(parameter) props: any
any
(alias) _jsxs(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsxs

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

const _components: any
any
(property) children: (string | React.ReactElement<any, string | React.JSXElementConstructor<any>>)[]
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function Thing(): React.ReactElement<any, string | React.JSXElementConstructor<any>>
function MDXContent(props?: {}): React.ReactElement<any, string | React.JSXElementConstructor<any>>
(parameter) props: {}
any
const MDXLayout: any
(parameter) props: {}
any
const MDXLayout: any
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

const MDXLayout: any
(parameter) props: {}
(property) children: React.ReactElement<any, string | React.JSXElementConstructor<any>>
(alias) _jsx(type: React.ElementType, props: unknown, key?: React.Key): React.ReactElement
import _jsx

Create a React element.

You should not use this function directly. Use JSX and a transpiler instead.

function _createMdxContent(props: any): React.ReactElement<any, string | React.JSXElementConstructor<any>>
(parameter) props: {}
function _createMdxContent(props: any): React.ReactElement<any, string | React.JSXElementConstructor<any>>
(parameter) props: {}

更多观察结果:

¥Some more observations:

  • JSX 被编译为函数调用和 React 的导入†

    ¥JSX is compiled away to function calls and an import of React†

  • 内容组件可以给 {components: {wrapper: MyLayout}} 来封装所有内容

    ¥The content component can be given {components: {wrapper: MyLayout}} to wrap all content

  • 内容组件可以指定 {components: {h1: MyComponent}} 以使用其他内容作为标题

    ¥The content component can be given {components: {h1: MyComponent}} to use something else for the heading

† MDX 未与 React 耦合。你还可以将其与 PreactVueEmotion主题界面 等一起使用。支持经典和自动 JSX 运行时。

¥† MDX is not coupled to React. You can also use it with Preact, Vue, Emotion, Theme UI, etc. Both the classic and automatic JSX runtimes are supported.

MDX 内容

¥MDX content

我们刚刚看到 MDX 文件被编译为组件。你可以像你选择的框架中的任何其他组件一样使用这些组件。获取这个文件:

¥We just saw that MDX files are compiled to components. You can use those components like any other component in your framework of choice. Take this file:

example.mdx
# Hi!

它可以在 React 应用中导入和使用,如下所示:

¥It could be imported and used in a React app like so:

example.jsx
import {createRoot} from 'react-dom/client'
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

const container = document.getElementById('root')
if (!container) throw new Error('Expected `root`')
const root = createRoot(container)
root.render(<Example />)
(alias) function createRoot(container: Container, options?: RootOptions): Root
import createRoot

createRoot lets you create a root to display React components inside a browser DOM node.

(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.
const container: HTMLElement | null
var document: Document
(method) Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

  • @param elementId String that specifies the ID value.
const container: HTMLElement | null
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
const root: Root
(alias) createRoot(container: Container, options?: RootOptions): Root
import createRoot

createRoot lets you create a root to display React components inside a browser DOM node.

const container: HTMLElement
const root: Root
(method) Root.render(children: React.ReactNode): 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.

主要内容作为默认导出导出。所有其他值也会被导出。举个例子:

¥The main content is exported as the default export. All other values are also exported. Take this example:

example.mdx
export function Thing() {
  return <>World</>
}

# Hello <Thing />

可以通过以下方式导入:

¥It could be imported in the following ways:

example.js
// A namespace import to get everything:
import * as everything from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
console.log(everything) // {Thing: [Function: Thing], default: [Function: MDXContent]}

// Default export shortcut and a named import specifier:
import Content, {Thing} from './example.mdx'
console.log(Content) // [Function: MDXContent]
console.log(Thing) // [Function: Thing]

// Import specifier with another local name:
import {Thing as AnotherName} from './example.mdx'
console.log(AnotherName) // [Function: Thing]
(alias) module "*.mdx"
import everything
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without calling require('console').

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
(alias) module "*.mdx"
import everything
import Content
(alias) function Thing(): JSX.Element
import Thing
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without calling require('console').

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
import Content
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without calling require('console').

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
(alias) function Thing(): JSX.Element
import Thing
function Thing(): JSX.Element
(alias) function AnotherName(): JSX.Element
import AnotherName
namespace console
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without calling require('console').

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
//   Error: Whoops, something bad happened
//     at [eval]:5:15
//     at Script.runInThisContext (node:vm:132:18)
//     at Object.runInThisContext (node:vm:309:38)
//     at node:internal/process/execution:77:19
//     at [eval]-wrapper:6:22
//     at evalScript (node:internal/process/execution:76:60)
//     at node:internal/main/eval_string:23:3

const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);

myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err

const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
(method) Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

  • @since v0.1.100
(alias) function AnotherName(): JSX.Element
import AnotherName

属性

¥Props

§ 什么是 MDX 中,我们展示了大括号内的 JavaScript 表达式可以在 MDX 中使用:

¥In § What is MDX, we showed that JavaScript expressions, inside curly braces, can be used in MDX:

example.mdx
import {year} from './data.js'
export const name = 'world'

# Hello {name.toUpperCase()}

The current year is {year}

数据也可以传递到 MDXContent,而不是在 MDX 中导入或定义数据。传递的数据称为 props。举个例子:

¥Instead of importing or defining data within MDX, data can also be passed to MDXContent. The passed data is called props. Take for example:

example.mdx
# Hello {props.name.toUpperCase()}

The current year is {props.year}

该文件可以用作:

¥This file could be used as:

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

// Use a `createElement` call:
console.log(React.createElement(Example, {name: 'Venus', year: 2021}))

// Use JSX:
console.log(<Example name="Mars" year={2022} />)
(alias) namespace React
import React
(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) namespace React
import React
function React.createElement<MDXProps>(type: React.FunctionComponent<MDXProps>, props?: (React.Attributes & MDXProps) | null | undefined, ...children: React.ReactNode[]): React.FunctionComponentElement<MDXProps> (+6 overloads)
(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) name: string
(property) year: number
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) name: string
(property) year: number

注意:MDX VS Code 扩展的用户可以使用 JSDoc 注释添加 props 的类型检查。请参阅 mdx-js/mdx-analyzer 了解更多信息。

¥Note: Users of the MDX VS Code extension can add type checking of props with a JSDoc comment. See mdx-js/mdx-analyzer for more info.

组件列表

¥Components

有一个特殊的属性:components。它需要一个将组件名称映射到组件的对象。举个例子:

¥There is one special prop: components. It takes an object mapping component names to components. Take this example:

example.mdx
# Hello *<Planet />*

它可以从 JavaScript 导入并传递组件,如下所示:

¥It can be imported from JavaScript and passed components like so:

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

console.log(
  <Example
    components={{
      Planet() {
        return <span style={{color: 'tomato'}}>Pluto</span>
      }
    }}
  />
)
(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(): JSX.Element
(property) JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
(property) React.HTMLAttributes<HTMLSpanElement>.style?: React.CSSProperties | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

ChromeFirefoxSafariEdgeIE
111123
(property) JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>

你不必传递组件。你还可以在 MDX 中定义或导入它们:

¥You don’t have to pass components. You can also define or import them within MDX:

example.mdx
import {Box, Heading} from 'rebass'

MDX using imported components!

<Box>
  <Heading>Here’s a heading</Heading>
</Box>

由于 MDX 文件是组件,因此它们也可以相互导入:

¥Because MDX files are components, they can also import each other:

example.mdx
import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License />

---

<Contributing />

以下是传递组件的其他一些示例:

¥Here are some other examples of passing components:

example.jsx
console.log(
  <Example
    components={{
      // Map `h1` (`# heading`) to use `h2`s.
      h1: 'h2',
      // Rewrite `em`s (`*like so*`) to `i` with a goldenrod foreground color.
      em(props) {
        return <i style={{color: 'goldenrod'}} {...props} />
      },
      // Pass a layout (using the special `'wrapper'` key).
      wrapper({components, ...rest}) {
        return <main {...rest} />
      },
      // Pass a component.
      Planet() {
        return 'Neptune'
      },
      // This nested component can be used as `<theme.text>hi</theme.text>`
      theme: {
        text(props) {
          return <span style={{color: 'grey'}} {...props} />
        }
      }
    }}
  />
)
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.

(property) h1?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(property) em?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>>
(parameter) props: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(property) JSX.IntrinsicElements.i: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(property) React.HTMLAttributes<HTMLElement>.style?: React.CSSProperties | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

ChromeFirefoxSafariEdgeIE
111123
(parameter) props: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(property) wrapper?: Component<any>

If a wrapper component is defined, the MDX content will be wrapped inside of it.

(parameter) components: any
(parameter) rest: any
(property) JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
(parameter) rest: any
(method) Planet(): string
(property) theme: {
    text(props: any): JSX.Element;
}
(method) text(props: any): JSX.Element
(parameter) props: any
(property) JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
(property) React.HTMLAttributes<T>.style?: React.CSSProperties | undefined
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

ChromeFirefoxSafariEdgeIE
111123
(parameter) props: any

可以在 components 中传递以下键:

¥The following keys can be passed in components:

  • 使用 Markdown 编写的内容的 HTML 等效项,例如 h1 对应 # heading(有关示例,请参阅 § 组件表

    ¥HTML equivalents for the things you write with markdown such as h1 for # heading (see § Table of components for examples)

  • wrapper,定义布局(但本地布局优先)

    ¥wrapper, which defines the layout (but a local layout takes precedence)

  • 对于你使用 JSX 编写的内容,任何其他有效的 JSX 标识符(fooQuotecustom-element_$xa1)(例如 <So /><like.so />,请注意本地定义的组件优先)‡

    ¥anything else that is a valid JSX identifier (foo, Quote, custom-element, _, $x, a1) for the things you write with JSX (like <So /> or <like.so />, note that locally defined components take precedence)

‡ JSX 中的名称(因此 <x> 中的 x)是否是字面量标签名称(如 h1)的规则如下:

¥ The rules for whether a name in JSX (so x in <x>) is a literal tag name (like h1) or not (like Component) are as follows:

  • 如果有一个点,则它是一个成员表达式(<a.b>h(a.b)),这意味着从对象 a 中获取对键 b 的引用

    ¥if there’s a dot, it’s a member expression (<a.b>h(a.b)), which means a reference to the key b taken from object a

  • 否则,如果名称不是有效的 JS 标识符,则它是一个字面量(<a-b>h('a-b')

    ¥otherwise, if the name is not a valid JS identifier, it’s a literal (<a-b>h('a-b'))

  • 否则,如果它以小写字母开头,则它是一个字面量(<a>h('a')

    ¥otherwise, if it starts with a lowercase, it’s a literal (<a>h('a'))

  • 否则,它是一个引用(<A>h(A)

    ¥otherwise, it’s a reference (<A>h(A))

components 中的这些键以及字面量标签名称和引用之间的区别如下所示。使用以下 MDX:

¥These keys in components and the difference between literal tag names and references is illustrated as follows. With the following MDX:

example.mdx

* [markdown syntax](#alpha)

* <a href="#bravo">JSX with a lowercase name</a>

* <Link to="#charlie">JSX with a capitalized name</Link>

…传递了一些组件:

¥…passed some components:

example.jsx
import Example from './example.mdx'

console.log(
  <Example
    components={{
      a(props) {
        return <a {...props} style={{borderTop: '1px dotted', color: 'violet'}} />
      },
      Link(props) {
        return <a href={props.to} children={props.children} style={{borderTop: '1px dashed', color: 'tomato'}} />
      }
    }}
  />
)
(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.

(property) a?: Component<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>>
(parameter) props: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(property) JSX.IntrinsicElements.a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(parameter) props: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(property) React.HTMLAttributes<HTMLAnchorElement>.style?: React.CSSProperties | undefined
(property) StandardShorthandProperties<string | number, string & {}>.borderTop?: Property.BorderTop<string | number> | undefined

The border-top shorthand CSS property sets all the properties of an element's top border.

Syntax: <line-width> || <line-style> || <color>

ChromeFirefoxSafariEdgeIE
111124
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

ChromeFirefoxSafariEdgeIE
111123
(method) Link(props: any): JSX.Element
(parameter) props: any
(property) JSX.IntrinsicElements.a: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>
(property) React.AnchorHTMLAttributes<HTMLAnchorElement>.href?: string | undefined
(parameter) props: any
any
(property) React.DOMAttributes<HTMLAnchorElement>.children?: React.ReactNode
(parameter) props: any
any
(property) React.HTMLAttributes<HTMLAnchorElement>.style?: React.CSSProperties | undefined
(property) StandardShorthandProperties<string | number, string & {}>.borderTop?: Property.BorderTop<string | number> | undefined

The border-top shorthand CSS property sets all the properties of an element's top border.

Syntax: <line-width> || <line-style> || <color>

ChromeFirefoxSafariEdgeIE
111124
(property) StandardLonghandProperties<string | number, string & {}>.color?: Property.Color | undefined

The color CSS property sets the foreground color value of an element's text and text decorations, and sets the currentcolor value. currentcolor may be used as an indirect value on other properties and is the default for other color properties, such as border-color.

Syntax: <color>

Initial value: canvastext

ChromeFirefoxSafariEdgeIE
111123

…我们会得到:

¥…we’d get:

请注意,第一个链接(#alpha)是带点的紫色。这是因为 a 是正在使用的 markdown 语法的 HTML 等效项。第二个链接(#bravo)保持不变,因为在 JSX 语法中 a 是一个字面量标签名称。第三个链接(#charlie)是虚线和番茄,因为在 JSX 语法中 Link 是一个引用。

¥Observe that the first link (#alpha) is dotted and violet. That’s because a is the HTML equivalent for the markdown syntax being used. The second link (#bravo) remains unchanged, because in JSX syntax a is a literal tag name. The third link (#charlie) is dashed and tomato, as in JSX syntax Link is a reference.

注意:MDX VS Code 扩展的用户可以使用 JSDoc 注释添加提供和传递的组件的类型检查。请参阅 mdx-js/mdx-analyzer 了解更多信息。

¥Note: Users of the MDX VS Code extension can add type checking of provided and passed components with a JSDoc comment. See mdx-js/mdx-analyzer for more info.

布局

¥Layout

有一个特殊的组件:布局。如果已定义,则用于封装所有内容。可以使用默认导出从 MDX 中定义布局:

¥There is one special component: the layout. If it is defined, it’s used to wrap all content. A layout can be defined from within MDX using a default export:

MDX
export default function Layout({children}) {
  return <main>{children}</main>;
}

All the things.

布局也可以使用 export … from 导入然后导出:

¥The layout can also be imported and then exported with an export … from:

MDX
export {Layout as default} from './components.js'

布局也可以作为 components.wrapper 传递(但本地布局优先)。

¥The layout can also be passed as components.wrapper (but a local one takes precedence).

MDX 提供商

¥MDX provider

你可能不需要提供者。传递组件通常没问题。提供商通常只会增加额外的重量。以这个文件为例:

¥You probably don’t need a provider. Passing components is typically fine. Providers often only add extra weight. Take for example this file:

post.mdx
# Hello world

像这样使用:

¥Used like so:

app.jsx
import {createRoot} from 'react-dom/client'
import {Heading, /* … */ Table} from './components.js'
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

const components = {
  h1: Heading.H1,
  // …
  table: Table
}

const container = document.getElementById('root')
if (!container) throw new Error('Expected `root`')
const root = createRoot(container)
root.render(<Post components={components} />)
(alias) function createRoot(container: Container, options?: RootOptions): Root
import createRoot

createRoot lets you create a root to display React components inside a browser DOM node.

(alias) const Heading: {
    H1: React.ComponentType;
}
import Heading
(alias) const Table: React.ComponentType<{}>
import Table
(alias) function Post(props: MDXProps): Element
import Post

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.
const components: {
    h1: React.ComponentType<{}>;
    table: React.ComponentType<{}>;
}
(property) h1: React.ComponentType<{}>
(alias) const Heading: {
    H1: React.ComponentType;
}
import Heading
(property) H1: React.ComponentType<{}>
(property) table: React.ComponentType<{}>
(alias) const Table: React.ComponentType<{}>
import Table
const container: HTMLElement | null
var document: Document
(method) Document.getElementById(elementId: string): HTMLElement | null

Returns a reference to the first object with the specified value of the ID attribute.

  • @param elementId String that specifies the ID value.
const container: HTMLElement | null
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
const root: Root
(alias) createRoot(container: Container, options?: RootOptions): Root
import createRoot

createRoot lets you create a root to display React components inside a browser DOM node.

const container: HTMLElement
const root: Root
(method) Root.render(children: React.ReactNode): void
(alias) function Post(props: MDXProps): Element
import Post

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.

const components: {
    h1: React.ComponentType<{}>;
    table: React.ComponentType<{}>;
}

有效,这些组件已被使用。

¥That works, those components are used.

但是,当你嵌套 MDX 文件(将它们相互导入)时,它可能会变得很麻烦。就像这样:

¥But when you’re nesting MDX files (importing them into each other) it can become cumbersome. Like so:

post.mdx
import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
import Contributing from './docs/contributing.mdx'

# Hello world

<License components={props.components} />

---

<Contributing components={props.components} />

为了解决这个问题,可以在 React、Preact 和 Vue 中使用 context。Context 提供了一种通过组件树传递数据的方法,而无需在每个级别手动向下传递 props。像这样设置:

¥To solve this, a context can be used in React, Preact, and Vue. Context provides a way to pass data through the component tree without having to pass props down manually at every level. Set it up like so:

  1. 安装 @mdx-js/react@mdx-js/preact@mdx-js/vue,具体取决于你使用的框架

    ¥Install either @mdx-js/react, @mdx-js/preact, or @mdx-js/vue, depending on what framework you’re using

  2. 配置 MDX 集成,并将 providerImportSourceProcessorOptions 设置为该包,因此 '@mdx-js/react''@mdx-js/preact''@mdx-js/vue'

    ¥Configure your MDX integration with providerImportSource in ProcessorOptions set to that package, so either '@mdx-js/react', '@mdx-js/preact', or '@mdx-js/vue'

  3. 从该包导入 MDXProvider。使用它来封装最顶层的 MDX 内容组件,并将其传递给你的 components

    ¥Import MDXProvider from that package. Use it to wrap your top-most MDX content component and pass it your components instead:

Diff
+import {MDXProvider} from '@mdx-js/react'
 import {createRoot} from 'react-dom/client'
 import {Heading, /* … */ Table} from './components/index.js'
 import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.
@@ -13,4 +14,8 @@ const components = {

 const container = document.getElementById('root')
 if (!container) throw new Error('Expected `root`')
 const root = createRoot(container)
-root.render(<Post components={components} />)
+root.render(
+  <MDXProvider components={components}>
+    <Post />
+  </MDXProvider>
+)

现在你可以删除显式且详细的组件传递:

¥Now you can remove the explicit and verbose component passing:

Diff
 import License from './license.md' // Assumes an integration is used to compile MDX -> JS.
 import Contributing from './docs/contributing.mdx'

 # Hello world

-<License components={props.components} />
+<License />

 ---

-<Contributing components={props.components} />
+<Contributing />

MDXProvider 嵌套时,它们的组件会合并。举个例子:

¥When MDXProviders are nested, their components are merged. Take this example:

JavaScript
console.log(
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider components={{h2: Component3, h3: Component4}}>
      <Content />
    </MDXProvider>
  </MDXProvider>
)
var console: Console
(method) Console.log(...data: any[]): void
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h1?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component1: React.ComponentType<{}>
import Component1
(property) h2?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component2: React.ComponentType<{}>
import Component2
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h2?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component3: React.ComponentType<{}>
import Component3
(property) h3?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component4: React.ComponentType<{}>
import Component4
(alias) const Content: MDXContent
import Content
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}

…这导致 h1 使用 Component1h2 使用 Component3h3 使用 Component4

¥…which results in h1s using Component1, h2s using Component3, and h3s using Component4.

要以不同方式合并或根本不合并,请将函数传递给 components。它给出了当前上下文 components,并且将使用它返回的内容。在此示例中,当前上下文组件被丢弃:

¥To merge differently or not at all, pass a function to components. It’s given the current context components and what it returns will be used instead. In this example the current context components are discarded:

JavaScript
console.log(
  <MDXProvider components={{h1: Component1, h2: Component2}}>
    <MDXProvider
      components={
        function () {
          return {h2: Component3, h3: Component4}
        }
      }
    >
      <Content />
    </MDXProvider>
  </MDXProvider>
)
var console: Console
(method) Console.log(...data: any[]): void
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h1?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component1: React.ComponentType<{}>
import Component1
(property) h2?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component2: React.ComponentType<{}>
import Component2
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(property) components?: Readonly<MDXComponents> | MergeComponents | null | undefined

Additional components to use or a function that creates them (optional).

(property) h2?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component3: React.ComponentType<{}>
import Component3
(property) h3?: Component<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>>
(alias) const Component4: React.ComponentType<{}>
import Component4
(alias) const Content: MDXContent
import Content
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}
(alias) function MDXProvider(properties: Readonly<Props>): React.ReactElement
import MDXProvider

Provider for MDX context.

  • @param properties Properties.
  • @returns Element.
  • @satisfies {Component}

…这导致 h2 使用 Component3h3 使用 Component4h1 未使用任何组件。

¥…which results in h2s using Component3 and h3s using Component4. No component is used for h1.

如果你不嵌套 MDX 文件,或者不经常嵌套它们,请不要使用提供程序:显式传递组件。

¥If you’re not nesting MDX files, or not nesting them often, don’t use providers: pass components explicitly.

MDX 中文网 - 粤ICP备13048890号