【问题标题】:How do I load a markdown file into a react component?如何将降价文件加载到反应组件中?
【发布时间】:2017-08-13 04:51:51
【问题描述】:

如何将 .md 降价文件加载到反应组件中?我通过google搜索尝试了很多npm库,但我找不到一个好的解决方案。

我想加载 .md 文件,例如:

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

【问题讨论】:

    标签: reactjs markdown


    【解决方案1】:

    我使用marked (GitHub)。

    我首先是这样导入的:

    import marked from "marked";
    

    然后我在 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)
          })
        })
    }
    

    ...最后我使用dangerouslySetInnerHTML 属性在页面上呈现它:

    render() {
      const { markdown } = this.state;
    
      return (
        <section>
          <article dangerouslySetInnerHTML={{__html: markdown}}></article>
        </section>
      )
    }
    

    【讨论】:

    • 尝试导入“标记”,Typescript 找不到声明文件
    • 我不熟悉 TypeScript,但你需要先安装包。 npm install marked --save 应该可以解决问题。
    • 啊,发现我需要安装类型定义才能让 Typescript 满意。 npmjs.com/package/@types/marked。谢谢我的朋友
    • 对我不起作用 ./src/pages/about.md 模块解析失败:/Users/me/myproject/src/pages/about.md 意外字符 '#' (1:0 ) 您可能需要适当的加载程序来处理此文件类型。 SyntaxError: 意外字符 '#' (1:0)
    • 查看stackoverflow.com/a/53975297/7784399 而不是这个。它不使用dangerouslySetInnerHTML 属性。
    【解决方案2】:

    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
    

    【讨论】:

    • 固体。感谢您的详细信息。您如何处理将您带到的重定向?
    • 我收到Cannot find module './Terms.fr.md' or its corresponding type declarations 错误。使用const termsFrPath = require './Terms.fr.md' 有效。
    【解决方案3】:

    您应该使用react-markdown 而不是accepted answer,此解决方案不使用dangerouslySetInnerHTML

    App.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!
    

    【讨论】:

    • 这也行不通 - Module parse failed: Unexpected token (1:4)
    • 我认为您需要在其他地方添加您必须拥有的东西,以便像 JS 文件一样将 MD 文件作为导入处理
    • @ToniLeigh 能否提供步骤
    • @Coderboi 加载程序?你的意思是?包管理器? NPM。
    • 当您不在 raw-loader 中将“.md”扩展名列入白名单时会出现问题,(是的,npm 包 raw-loader)...把它放在 webpack 中解决了我的问题。
    【解决方案4】:

    markdown-to-jsx 提供了非常高效的功能来与 React 组件中的 markdown 进行交互。

    它允许用您的自定义组件替换/覆盖任何 HTML 元素以用于降价,here is the 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
    

    21 年 8 月 2 日编辑

    功能组件
    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>
        )
    }
    

    【讨论】:

    • 这会产生:找不到模块:无法解析'./README.md'
    • 是否需要像 github.com/peerigon/markdown-loader/blob/master/example/… 这样的自定义加载器?
    • 我觉得你需要一个文件加载器,你也可以试试 md-loader。
    • 我在没有加载器的create-react-app中使用过。
    • 遇到此错误的人,只需在 webpack 的 raw-loader 模块中添加 .md 扩展名
    【解决方案5】:

    类似于@Xing-Han-Lu 的回答,但对 Markdown 有反应。该概念使用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} />
        </>
      );
    }
    

    【讨论】:

      【解决方案6】:

      使用 webpack 加载器的方法

      安装 raw-loader

      npm install raw-loader --save-dev
      

      更新 webpack.config.js

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

      创建降价文件(比如App.md

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

      导入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;
      

      【讨论】:

        【解决方案7】:

        对于 Typescript + react,请按照以下步骤操作:

        1. 在项目目录之一中创建一个类型定义index.d.ts)文件,并放入以下代码。
        declare module "*.md";
        
        1. 添加tsconfig.json -&gt; CompilerOptions -&gt; typeRoots如下
        {
             "compilerOptions": {
                 ...
                 "typeRoots": [ "<types-directory-created-in-#1>", "./node_modules/@types"],
                 ...
             }
        }
        
        1. 安装两个库showdownhtml-react-parser

        yarn add showdownnpm install showdown

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

        1. 在您的组件中
        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>
            )
        }
        

        【讨论】:

          【解决方案8】:

          我稍微修改了这个solution 以使用钩子和useEffect(这与componentWillUpdate 不同,但仍然有效)。如果您使用 create-react-app 构建了您的应用,并且您有一个名为 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;
          
          

          【讨论】:

            【解决方案9】:

            如果您使用 Webpack(即Electron React Boilerplate),那么您可以通过使用 Webpack 加载器来节省几个步骤。

            npm i -D html-loader markdown-loader marked
            

            在 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
                    }
                  }
                ]
              }
            

            然后,在 React 组件中,它只是一个要求和设置 HTML。

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

            最后,Flow 会在导入 markdown 文件时报错(仍然有效)。将此添加到 .flowconfig 以使 Flow 将 md 文件视为字符串资产(由 Webpack 负责):

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

            【讨论】:

            • 谢谢!这对我有用,我认为使用加载器比在浏览器中进行降价渲染更好。
            【解决方案10】:

            我已经尝试了上述建议,并在运行命令后推断出

            > npm install markdown
            
            import ReactMarkdown from 'markdown';
            

            它终于对我有用了

            【讨论】:

              【解决方案11】:

              我希望它使用 react-markdown 使用动态导入来工作。我的 general 代码如下,您必须添加一个 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);
                  }
                };
              

              const readmePath = await require("" + location); 中需要添加空字符串 (hehe)。我是从here 那里得到的。我不知道它为什么有效。

              【讨论】:

                【解决方案12】:

                另一种选择是将 Markdown 放在 .js 文件中,使用反引号 ` 字符将 Markdown 作为未标记的模板文字括起来。像这样:

                const MD = `
                **TERMS OF SERVICE**
                
                Last Modified: 30 November 2021...`
                
                export default MD
                

                然后你可以像任何其他模块一样import它。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-07-01
                  • 1970-01-01
                  • 2020-02-13
                  • 2019-08-26
                  • 2020-05-17
                  • 2021-08-25
                  • 2019-08-08
                  • 2021-11-08
                  相关资源
                  最近更新 更多