MDX와 리액트
마크다운에서 JSX 사용하기
도큐사우루스는 MDX v1를 기본 지원합니다. MDX를 기반으로 마크다운 파일 내에 JSX를 작성해서 리액트 컴포넌트를 표현할 수 있습니다.
도큐사우루스는 MDX를 사용해 .md
, .mdx
파일을 모두 구문 분석하지만 일부 구문은 서드파티 도구에서 약간 다르게 처리됩니다. 좀 더 정확한 구문 해석과 에디터 지원을 위해 MDX 문법을 포함한 .mdx
파일 확장자를 사용하는 것을 권장합니다.
MDX 문서에서 MDX를 이용해 만들 수 있는 멋진 것들을 찾아보세요.
컴포넌트 내보내기
To define any custom component within an MDX file, you have to export it: only paragraphs that start with export
will be parsed as components instead of prose.
export const Highlight = ({children, color}) => (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
<Highlight color="#25c2a0">도큐사우루스 초록</Highlight>과 <Highlight color="#1877F2">페이스북 파랑</Highlight>은 내가 좋아하는 색입니다.
**마크다운**을 _JSX_와 같이 사용할 수 있습니다!
Notice how it renders both the markup from your React component and the Markdown syntax:
도큐사우루스 초록 과 페이스북 파랑은 내가 좋 아하는 색입니다.
마크다운을 _JSX_와 같이 사용할 수 있습니다!
Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects.
/* 이렇게 쓰지 말고: */
<span style="background-color: red">Foo</span>
/* 이렇게 쓰세요: */
<span style={{backgroundColor: 'red'}}>Foo</span>
This behavior is different from Docusaurus 1. See also Migrating from v1 to v2.
In addition, MDX is not 100% compatible with CommonMark. Use the MDX playground to ensure that your syntax is valid MDX.
컴포넌트 가져오기
You can also import your own components defined in other files or third-party components installed via npm.
<!-- 도큐사우루스 테마 컴포넌트 -->
import TOCInline from '@theme/TOCInline';
<!-- 외부 컴포넌트 -->
import Button from '@mui/material/Button';
<!-- 사용자 지정 컴포넌트 -->
import BrowserWindow from '@site/src/components/BrowserWindow';
The @site
alias points to your website's directory, usually where the docusaurus.config.js
file is. Using an alias instead of relative paths ('../../src/components/BrowserWindow'
) saves you from updating import paths when moving files around, or when versioning docs and translating.
While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate .js
file when your component involves complex JS logic:
import React from 'react';
export default function Highlight({children, color}) {
return (
<span
style={{
backgroundColor: color,
borderRadius: '2px',
color: '#fff',
padding: '0.2rem',
}}>
{children}
</span>
);
}
import Highlight from '@site/src/components/Highlight';
<Highlight color="#25c2a0">도큐사우루스 초록</Highlight>
If you use the same component across a lot of files, you don't need to import it everywhere—consider adding it to the global scope. See below
MDX 컴포넌트 스코프
Apart from importing a component and exporting a component, a third way to use a component in MDX is to register it to the global scope, which will make it automatically available in every MDX file, without any import statements.
For example, given this MDX file:
- a
- list!
And some <Highlight>custom markup</Highlight>...
It will be compiled to a React component containing ul
, li
, p
, and Highlight
elements. Highlight
is not a native html element: you need to provide your own React component implementation for it.
In Docusaurus, the MDX component scope is provided by the @theme/MDXComponents
file. It's not a React component, per se, unlike most other exports under the @theme/
alias: it is a record from tag names like Highlight
to their React component implementations.
If you swizzle this component, you will find all tags that have been implemented, and you can further customize our implementation by swizzling the respective sub-component, like @theme/MDXComponents/Code
(which is used to render Markdown code blocks).
If you want to register extra tag names (like the <Highlight>
tag above), you should consider wrapping @theme/MDXComponents
, so you don't have to maintain all the existing mappings. Since the swizzle CLI doesn't allow wrapping non-component files yet, you should manually create the wrapper:
import React from 'react';
// 원본 mapper 가져오기
import MDXComponents from '@theme-original/MDXComponents';
import Highlight from '@site/src/components/Highlight';
export default {
// 기본 mapping 재사용
...MDXComponents,
// "<Highlight>" 태그를 여러분이 만든 Highlight 컴포넌트에 매핑하세요.
// `Highlight`는 MDX에서 `<Highlight>`로 전달된 모든 속성을 수신합니다.
Highlight,
};
And now, you can freely use <Highlight>
in every page, without writing the import statement:
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
I can conveniently use Docusaurus green everywhere!
We use upper-case tag names like Highlight
on purpose.
From MDX v2+ onward (Docusaurus v3+), lower-case tag names are always rendered as native html elements, and will not use any component mapping you provide.
This feature is powered by a wrapper provider. If you are importing Markdown in a React page, you have to supply this provider yourself through the MDXContent
theme component.
import React from 'react';
import FeatureDisplay from './_featureDisplay.mdx';
import MDXContent from '@theme/MDXContent';
export default function LandingPage() {
return (
<div>
<MDXContent>
<FeatureDisplay />
</MDXContent>
</div>
);
}
If you don't wrap your imported MDX with MDXContent
, the global scope will not be available.
마크다운과 JSX 상호 운용성
Docusaurus v2 is using MDX v1, which has a lot of known cases where the content fails to be correctly parsed as Markdown. Use the MDX playground to ensure that your syntax is valid MDX.
Samples of parsing failures
A paragraph starting with a JSX tag will be seen entirely as a JSX string:
- Problem
- Workaround
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
Highlighted text but afterwards Markdown doesn't work
줄의 나머지 부분에 JSX를 사용하거나 일반 텍스트를 접두어로 사용하세요.
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
Use JSX for the paragraph to stop worrying about Markdown
← This is a zero-width space and afterwards Markdown works
JSX 태그 내에서 마크다운은 작동하지 않습니다.
- Problem
- Workaround
<span style={{color: 'red'}}>**Bold doesn't work**</span>
JSX 태그 내에서 JSX를 사용하거나 마크다운을 외부 레이어로 이동합니다.
<span style={{color: 'red'}}><b>Bold now works</b></span>
**<span style={{color: 'red'}}>Bold now works</span>**
Bold now works
JSX 태그 바로 아래에 있는 텍스트는 JSX 텍스트로 표시됩니다.
- Problem
- Workaround
<div style={{color: 'red'}}>
**Bold still doesn't work**
</div>
Bold still doesn't work
새 줄을 추가합니다.
<div style={{color: 'red'}}>
**Bold now works**
</div>
Bold now works
4개의 공백문자로 들여쓴 마크다운 텍스트는 코드 블록으로 표시됩니다.
- Problem
- Workaround
<div style={{color: 'red'}}>
You may think I'm just some text...
</div>
You may think I'm just some text...
들여쓰지 마세요.
<div style={{color: 'red'}}>
Now I'm actually just text
</div>
Now I'm actually just text
Importing code snippets
You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to Webpack raw-loader. In order to use raw-loader
, you first need to install it in your project:
- npm
- Yarn
- pnpm
npm install --save raw-loader
yarn add raw-loader
pnpm add raw-loader
Now you can import code snippets from another file as it is:
import CodeBlock from '@theme/CodeBlock';
import MyComponentSource from '!!raw-loader!./myComponent';
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {useState} from 'react';
export default function MyComponent() {
const [bool, setBool] = useState(false);
return (
<div>
<p>MyComponent rendered !</p>
<p>bool={bool ? 'true' : 'false'}</p>
<p>
<button onClick={() => setBool((b) => !b)}>toggle bool</button>
</p>
</div>
);
}
See using code blocks in JSX for more details of the <CodeBlock>
component.
You have to use <CodeBlock>
rather than the Markdown triple-backtick ```
, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.
This feature is experimental and might be subject to breaking API changes in the future.
Importing Markdown
You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages.
By convention, using the _
filename prefix will not create any doc page and means the Markdown file is a "partial", to be imported by other files.
<span>Hello {props.name}</span>
This is text some content from `_markdown-partial-example.mdx`.
import PartialExample from './_markdown-partial-example.mdx';
<PartialExample name="Sebastien" />
_markdown-partial-example.md
에서 가져온 텍스트입니다.
This way, you can reuse content among multiple pages and avoid duplicating materials.
Currently, the table of contents does not contain the imported Markdown headings. This is a technical limitation that we are trying to solve (issue).
Available exports
Within the MDX page, the following variables are available as globals:
frontMatter
: the front matter as a record of string keys and values;toc
: the table of contents, as a tree of headings. See also Inline TOC for a more concrete use-case.contentTitle
: the Markdown title, which is the firsth1
heading in the Markdown text. It'sundefined
if there isn't one (e.g. title specified in the front matter).
import TOCInline from '@theme/TOCInline';
import CodeBlock from '@theme/CodeBlock';
The table of contents for this page, serialized:
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
The front matter of this page:
<ul>
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
</ul>
<p>The title of this page is: <b>{contentTitle}</b></p>
The table of contents for this page, serialized:
[
{
"value": "마크다운에서 JSX 사용하기",
"id": "using-jsx-in-markdown",
"level": 2
},
{
"value": "컴포넌트 내보내기",
"id": "exporting-components",
"level": 3
},
{
"value": "컴포넌트 가져오기",
"id": "importing-components",
"level": 3
},
{
"value": "MDX 컴포넌트 스코프",
"id": "mdx-component-scope",
"level": 3
},
{
"value": "마크다운과 JSX 상호 운용성",
"id": "markdown-and-jsx-interoperability",
"level": 3
},
{
"value": "Importing code snippets",
"id": "importing-code-snippets",
"level": 2
},
{
"value": "Importing Markdown",
"id": "importing-markdown",
"level": 2
},
{
"value": "Available exports",
"id": "available-exports",
"level": 2
}
]
The front matter of this page:
- id: react
- description: MDX를 사용해 도큐사우루스 마크다운 문서 내에서 리액트의 강력한 기능을 활용할 수 있습니다.
- slug: /markdown-features/react
The title of this page is: MDX와 리액트