5

I use markdown-to-jsx to render markdown in my React component.

My problem is that I want to dynamically load the markdown file, instead of specifying it with import. The scenario is that this happens on an article details page, i.e. I get the articleId from the route params and then based on that id, I want to load the corresponding markdown file, e.g. article-123.md.

Here's what I have so far. How can I load the md file dynamically?

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

class Article extends Component {
  constructor(props) {
    super(props)
    this.state = { md: '' }
  }

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

  render() {
    return (
      <div className="article">
        <Markdown children={this.state.md}/>
      </div>
    )
  }
}

export default Article

This works fine as is, but if I remove import articleMd from './article-123.md' at the top and instead pass the file path directly to fetch it output what looks like index.html, not the expected md file.

5
  • hello, where is it the actual *.md file ? According to its path/position, if you remove the import, it could be that's not included in the webpack output and then the Express dev server will serve you index.html Commented Aug 26, 2019 at 8:40
  • The .md file is in the same directory as the component that imports it. To be clear, I don't see index.html, I still see my component. But within my component, instead of the content of the md file, it renders the content of what looks like index.html, starting with <!DOCTYPE html>. Commented Aug 26, 2019 at 8:45
  • 1
    Do I need to tell Webpack to include all my md files in the output? How? Commented Aug 26, 2019 at 8:46
  • 1
    usually you can modifiy in webpack.config.js to add a path containing your .md files to be included in the output, but if you use create-react-app you can't (unless you eject it)... in this latter case, you should place your md files within the public folder Commented Aug 26, 2019 at 8:58
  • check this for more reference: create-react-app.dev/docs/using-the-public-folder Commented Aug 26, 2019 at 9:09

2 Answers 2

4

Can't you use dynamic import?

class Article extends React.Component {
    constructor(props) {
        super(props)
        this.state = { md: '' }
    }

    async componentDidMount() {
        const articleId = this.props.params.articleId; // or however you get your articleId
        const file = await import(`./article-${articleId}.md`);
        const response = await fetch(file.default);
        const text = await response.text();

        this.setState({
            md: text
        })
    }

    render() {
        return (
            <div className="article">
                <Markdown children={this.state.md} />
            </div>
        )
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

The dynamic import is a good feature when you want to lazily load some well defined javascript, like a Component to be rendered with React.lazy. If it is used like that, I guess that he would have the same problem he currently has ... index.html would get loaded, instead of the actual md, because webpack won't include the md in the build output.
This code returns .md file content correctly, since I've tested it. Difference with his code is usage of dynamic import, where file.default returns relative path to the .md file and that part is passed to the fetch (in his example, he tried using './article-123.md' directly in fetch, and not generated relative path). 'file.default' returns something like '/static/media/generated-string.md'.
I see, you're right ! I was sure that webpack would exclude the *.md files from the bundle but it does not, it does do the job... good to know thx.
1

I know this is an old thread but I just solved this issue with the following code using markdown-to-jsx

import React, { Component } from 'react'
import Markdown from 'markdown-to-jsx'

    class Markdown_parser extends Component {
        
        
      constructor(props) {
        super(props)
        
        this.state = { md: "" }
      }
    
      componentWillMount() {
        const { path } = this.props;
        import(`${path}`).then((module)=>
        
        fetch(module.default)
          .then((res) => res.text())
          .then((md) => {
            this.setState({ md })
          })
        )
      }
    
      render() {
    
        let { md } = this.state
    
        return (
          <div className="post">
            <Markdown children={md} />
          </div>
        )
      }
    }
    
    export default Markdown_parser

I then call the class sa follows

<Markdown_parser path = "path-to-your-fle" />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.