简体   繁体   English

如何将 Markdown 文件加载到 React 组件中?

[英]How do I load a markdown file into a react component?

How would I load a .md markdown file into a react component?我如何将 .md 降价文件加载到反应组件中? I have tried so many npm libraries through google searches and I cant find a good solution.我通过谷歌搜索尝试了很多 npm 库,但找不到好的解决方案。

代码图片

I want to load the .md file something like:我想加载 .md 文件,例如:

render() {
    <div>
        <MarkDown src="about.md" />
    </div>
}

I use marked ( GitHub ).我使用标记GitHub )。

I first import it like this:我首先像这样导入它:

import marked from "marked";

I then fetch my *.md file within React's componentDidMount event and store it in my component's state using marked(text) (where text is the response):然后我在 React 的componentDidMount事件中获取我的 *.md 文件并使用marked(text) (其中text是响应)将其存储在我的组件状态中:

componentDidMount() {
  const readmePath = require("./Readme.md");

  fetch(readmePath)
    .then(response => {
      return response.text()
    })
    .then(text => {
      this.setState({
        markdown: marked(text)
      })
    })
}

...and finally I render it on the page using the dangerouslySetInnerHTML attribute: ...最后我使用dangerouslySetInnerHTML属性在页面上呈现它:

render() {
  const { markdown } = this.state;

  return (
    <section>
      <article dangerouslySetInnerHTML={{__html: markdown}}></article>
    </section>
  )
}

A full working example with react-markdown :一个带有react-markdown完整工作示例:

import React, { Component } from 'react'
import ReactMarkdown from 'react-markdown'
import termsFrPath from './Terms.fr.md'

class Terms extends Component {
  constructor(props) {
    super(props)

    this.state = { terms: null }
  }

  componentWillMount() {
    fetch(termsFrPath).then((response) => response.text()).then((text) => {
      this.setState({ terms: text })
    })
  }

  render() {
    return (
      <div className="content">
        <ReactMarkdown source={this.state.terms} />
      </div>
    )
  }
}

export default Terms

You should use react-markdown instead of the accepted answer , this solution doesn't use dangerouslySetInnerHTML .您应该使用react-markdown而不是接受的答案,此解决方案不使用dangerouslySetInnerHTML

App.js应用程序.js

import React, { Component } from 'react';
import AppMarkdown from './App.md';
import ReactMarkdown from 'react-markdown';

class App extends Component {

  constructor() {
    super();
    this.state = { markdown: '' };
  }

  componentWillMount() {
    // Get the contents from the Markdown file and put them in the React state, so we can reference it in render() below.
    fetch(AppMarkdown).then(res => res.text()).then(text => this.setState({ markdown: text }));
  }

  render() {
    const { markdown } = this.state;
    return <ReactMarkdown source={markdown} />;
  }
}

export default App;

App.md应用程序

# React & Markdown App
* Benefits of using React... but...
* Write layout in Markdown!

markdown-to-jsx provides very efficeint functionality to interact with markdown in React component. markdown-to-jsx提供了非常有效的功能来与 React 组件中的 markdown 交互。

It allows replacing/overriding of any HTML element with your Custom Component for markdown, here is the doc .它允许使用您的自定义组件替换/覆盖任何 HTML 元素以进行降价, 这里是 doc

import React, { Component } from 'react'
import Markdown from 'markdown-to-jsx';
import README from './README.md'

class PageComponent extends Component {
  constructor(props) {
    super(props)

    this.state = { md: "" }
  }

  componentWillMount() {
    fetch(README)
      .then((res) => res.text())
      .then((md) => {
        this.setState({ md })
      })
  }

  render() {

    let { md } = this.state

    return (
      <div className="post">
        <Markdown children={md}/>
      </div>
    )
  }
}

export default PageComponent

Edit 2nd Aug'21 21 年 8 月 2 日编辑

Functional Component功能组件
const PageComponent = ()=> {

    let [ content, setContent] = useState({md: ""});

    useEffect(()=> {
        fetch(README)
            .then((res) => res.text())
            .then((md) => {
                setContent({ md })
            })
    }, [])

    return (
      <div className="post">
        <Markdown children={content.md}/>
      </div>
    )
}

Similar to @Xing-Han-Lu's answer but with react Markdown.与@Xing-Han-Lu 的回答类似,但使用 Markdown 反应。 The concept uses useEffect to load up the file then adds it to state using the useState hook where it's accessible to reactMarkdown该概念使用useEffect加载该文件,然后使用它添加到状态useState钩它的访问reactMarkdown

import React, { useState, useEffect } from "react";
import ReactMarkdown from "react-markdown";
import file from "./md/posts.md";

export default function () {
  const [markdown, setMarkdown] = useState("");

  useEffect(() => {
    fetch(file)
      .then((res) => res.text())
      .then((text) => setMarkdown(text));
  }, []);

  return (
    <>
      <ReactMarkdown source={markdown} />
    </>
  );
}

For Typescript + react please follow below steps:对于Typescript + react,请按照以下步骤操作:

  1. Create one type definition ( index.d.ts ) file in one of the project directory and put the following code.在项目目录之一中创建一个类型定义index.d.ts )文件并放置以下代码。
declare module "*.md";
  1. Add tsconfig.json -> CompilerOptions -> typeRoots as following添加tsconfig.json -> CompilerOptions -> typeRoots如下
{
     "compilerOptions": {
         ...
         "typeRoots": [ "<types-directory-created-in-#1>", "./node_modules/@types"],
         ...
     }
}
  1. Install two libraries showdown and html-react-parser安装两个库showdownhtml-react-parser

yarn add showdown or npm install showdown yarn add showdownnpm install showdown

yarn add html-react-parser or npm install html-react-parser yarn add html-react-parsernpm install html-react-parser

  1. In your component在您的组件中
import React, { useEffect, useState } from 'react';
import showdown from 'showdown';
import parse from 'html-react-parser';
import readme from 'path/filename.md';

export default function ComponentName() {
    const [html, setHTML] = useState("");

    //Use componentDidMount(): if class based component to load md file
    useEffect(() => {
        fetch(readme)
            .then(data => data.text())
            .then(text => {
                const converter = new showdown.Converter();
                setHTML(converter.makeHtml(text));
            })
    }, []);

    return (
        <div>{parse(html)}</div>
    )
}

I slightly modified this solution to use hooks and useEffect (which is different from componentWillUpdate but still works).我稍微修改这个解决方案,以使用钩子和useEffect (这是从不同的componentWillUpdate但仍然有效)。 If you built your app with create-react-app and you have a markdown document called document.md , you can build your app in the following way:如果您使用 create-react-app 构建您的应用程序并且您有一个名为document.md的降价document.md ,您可以通过以下方式构建您的应用程序:

import { useState, useEffect } from 'react';
import Markdown from 'markdown-to-jsx';
import mdDocument from './document.md';

const App = () => {
  const [content, setContent] = useState("");

  useEffect(() => {
    fetch(mdDocument)
      .then(res => res.text())
      .then(md => { setContent(md) })
  })

  return (
    <div><Markdown children={content} /></div>
  )
}

export default App;

Approach using webpack loader使用 webpack loader 的方法

Install raw-loader安装原始加载器

npm install raw-loader --save-dev

Update webpack.config.js更新webpack.config.js

module.exports = {
  //...
  module: {
    rules: [
      // ...
      {
        test: /\.md$/,
        use: "raw-loader",
      },
    ],
  },
};

Create markdown file (say App.md )创建降价文件(比如App.md

# React & Markdown App

- Benefits of using React... but...
- Write layout in Markdown!

Import App.md and use it in React component.导入App.md并在 React 组件中使用它。

import React from "react";
import ReactMarkdown from 'react-markdown';
import AppMarkdown from './App.md';

function App() {
  return (
    <div>
      <ReactMarkdown children={`${AppMarkdown}`} />
    </div>
  );
}

export default App;

If you use Webpack (ie Electron React Boilerplate ) then you can save a few steps by using Webpack loaders.如果您使用 Webpack(即Electron React Boilerplate ),那么您可以通过使用 Webpack 加载器来节省几个步骤。

npm i -D html-loader markdown-loader marked

In webpack.config.renderer.dev.js:在 webpack.config.renderer.dev.js 中:

import marked from 'marked';
const markdownRenderer = new marked.Renderer();

....

  // Markdown
  {
    test: /\.md$/,
    use: [
      {
        loader: 'html-loader'
      },
      {
        loader: 'markdown-loader',
        options: {
          pedantic: true,
          renderer: markdownRenderer
        }
      }
    ]
  }

Then, in the React component it's simply a require and setting the HTML.然后,在 React 组件中,它只是一个 require 和设置 HTML。

import knownIssues from '../assets/md/known-issues.md';
....
<p dangerouslySetInnerHTML={{ __html: knownIssues }} />

Lastly, Flow will report an error (it still works) when importing the markdown file.最后,Flow在导入markdown文件时会报错(它仍然有效)。 Add this to .flowconfig to make Flow treat md files as string assets (care of Webpack):将此添加到 .flowconfig 以使 Flow 将 md 文件视为字符串资产(Webpack 的注意事项):

module.name_mapper.extension='md' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'

I have tried the above suggestions and deduced that after running a command我已经尝试了上述建议并在运行命令后推断出

> npm install markdown
import ReactMarkdown from 'markdown';

it finally worked for me它终于对我有用了

I wanted it to work using dynamic imports using react-markdown .我希望它使用react-markdown使用动态导入工作。 My general code is below, you'll have to add a useEffect to call the function and put a reference to the state variable in the function return:我的一般代码如下,您必须添加一个 useEffect 来调用该函数并在函数返回中放置对状态变量的引用:

  const [displayElement, setDisplayElement] = useState(null);

  //Get markdown file
  const fetchMarkdown = async (location) => {
    console.log("MD location: ", location);
    try {
      //I figured out readmePath.default using print statements, left there in case
      //someone wants them
      const readmePath = await require("" + location);
      //console.log(readmePath);
      const response = await fetch(readmePath.default);
      //console.log("response => ", response);
      const text = await response.text();
      //console.log(text);

      // the state variable I am setting the markdown into, in my render function 
      // I have {displayElement}.
      setDisplayElement(
        <div className={styles.markdownContainer}>
          <ReactMarkdown children={text} />
        </div>
      );
    } catch (e) {
      console.log("Markdown file: couldn't read =>", location, e);
    }
  };

The addition of the empty string in const readmePath = await require("" + location); const readmePath = await require("" + location);中空字符串的添加const readmePath = await require("" + location); is required ( hehe ).是必需的(呵呵)。 I got that from here .我从这里得到的。 I don't know why it works.我不知道它为什么有效。

Another option is to put the Markdown in a .js file, using the backtick ` character to enclose the Markdown as an untagged template literal.另一种选择是将 Markdown 放在 .js 文件中,使用反引号 ` 字符将 Markdown 作为未标记的模板文字括起来。 Like this:像这样:

const MD = `
**TERMS OF SERVICE**

Last Modified: 30 November 2021...`

export default MD

Then you can import it like any other module.然后您可以像import任何其他模块一样import它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM