如何将降价文件加载到反应组件中?

Posted

技术标签:

【中文标题】如何将降价文件加载到反应组件中?【英文标题】: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>

【问题讨论】:

【参考方案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) 查看***.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,请按照以下步骤操作:

    在项目目录之一中创建一个类型定义index.d.ts)文件,并放入以下代码。
declare module "*.md";
    添加tsconfig.json -&gt; CompilerOptions -&gt; typeRoots如下

     "compilerOptions": 
         ...
         "typeRoots": [ "<types-directory-created-in-#1>", "./node_modules/@types"],
         ...
     

    安装两个库showdown和html-react-parser

yarn add showdownnpm install showdown

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

    在您的组件中
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它。

【讨论】:

以上是关于如何将降价文件加载到反应组件中?的主要内容,如果未能解决你的问题,请参考以下文章

反应导入组件文件夹[重复]

如何将状态值从一个组件访问到位于单独文件中的其他功能(不是组件)?反应js

如何使用钩子将 React 类组件转换为功能组件

反应如何访问 JSON 文件中的对象

在页面加载时将道具传递给子组件 - 与 next.js 做出反应

无法将 scss 文件导入到反应组件中