Photo (c) Mike Wilson

Build a Markdown Previewer with Reactjs

Hi! I’m back.

We’re going to delve right in building projects with React and Sass.

If you’re just new to Sass, I suggest reading their guide on their website. And try it out on CodePen. Then, learn on running Sass in your local editor. (And that gives me another idea for a blog post.)

We’re going to build a Markdown Previewer. And we want to accomplish the following user stories.

  1. I can type GitHub-flavored Markdown into a text area.
  2. I can see a preview of the output of my markdown that is updated as I type.

Hint: You don’t need to interpret Markdown yourself – you can import the Marked library for this: https://cdnjs.com/libraries/marked

In this blog, I used CodePen.

How to Set Up React and Sass on CodePen

  1. Create New Pen.
  2. Click the settings icon beside the word, ‘JavaScript’. The pen settings will appear.
  3. In the JavaScript preprocessor, select ‘Babel’.
  4. In the Add External JavaScript section, you can see quick add in the bottom part.
  5. Select ‘React’.
  6. Select ‘React DOM’.
  7. Under the Pen Settings label, click ‘CSS’ beside the JavaScript label.
  8. In the CSS preprocessor, select Sass’.
  9. Finally, click ‘Save & Close’.

Markup

I also used Bootstrap here if you want to add a Bootstrap CDN on CodePen. Just paste it in the box under the label ‘Add External CSS’ in the ‘CSS’ section of the Pen Settings.

<div class="container">
  <h1 class="text-center">Build a Markdown Previewer</h1>

  <div id="root" >
  </div>
  
  <footer>
    <p class="text-center">by <a href="http://eiringonzales.com/" target="_blank">eirin gonzales</a></p>
  </footer>
</div>

Styles

body
  padding-top: 40px
  width: 100%
  background-color: #000
  color: #fff
  box-sizing: border-box
  
.text-center
  color: #fff
  padding-bottom: 20px
  font-family: 'Delius Unicase', cursive
  
textarea
  font-family: 'Open Sans', sans-serif
  font-size: 16px
  padding: 20px
  overflow: scroll
 
footer
  p
    font-family: 'Delius Unicase', cursive
  a:hover
    color: grey

Indentation in Sass has a significant meaning. So be careful with that so you won’t get errors.

Script

This is the meat of our app. The textarea and the preview of the text will be generated by our scripts.

What I like about ReactJS is that it gives you a way to organize your code into components.

And the first component we’ll be building is the textarea.

class TypeArea extends React.Component {
  constructor() {
    super();
    this.state = {
           message: 'Heading\n=======\n\nSub-heading\n-----------\n
 \n### Another deeper heading\n \nParagraphs are separated\nby a 
blank line.\n\nLeave 2 spaces at the end of a line to do a  \nline
 break\n\nText attributes *italic*, **bold**, \n`monospace`,
 ~~strikethrough~~ .\n\nShopping list:\n\n  * apples\n  * oranges\n
  * pears\n\nNumbered list:\n\n  1. apples\n  2. oranges\n  3. 
pears\n\nThe rain---not the reign---in\nSpain.\n\n 
*[Herman Fassett](https://freecodecamp.com/hermanfassett)*'
    };
    this.handleChange = this.handleChange.bind(this);
  }
  
  handleChange() {
    this.setState({
      message: event.target.value
    });
  }
  
  render() {
    
    return (
      <div className="row">
        <div className="col-xs-12 col-md-6">
          <form>
            <textarea rows="20" cols="35" value={this.state.message} onChange={this.handleChange}>
            </textarea>
          </form>
        </div>
        <Preview message={this.state.message} />
      </div>
    );
  }
}

We’re using ES6 class to define our component named TypeArea.

So in this component, we’re going to generate our markup for the textarea and the preview of the text.

TypeArea

Constructor

  1. We have a super method. You need to call it if you have a constructor because you have to initialize this’. Read the first answer from this site for more.
  2. We define our states after that method. States are like private properties accessible within the component. We initialized our message state here so our app will display something if it loads. The way we call the properties or states inside this is this.state.message., this.state. then the name of the state.
  3. We also bind one method here so if we call our method, it will not be undefine. And according to React Docs, binding is necessary. If you create methods inside your component, you should bind it. You can also bind it where you’re going to use it but I prefer binding methods in the constructor rather than they’re spread out through the code.

User-defined Methods

After the constructor, we define our methods here.

  1. Our one method named handleChange will be called every time there’s a change in our textarea.
  2. And what it does is change the value of our state. It sets the new content of our this.state.message.
  3. To change the state, you have to call the built-in function called setState(). Then, set the new value there. Every time your state changes its value, the render method is called. It’s supposed to do that but sometimes, it’s not doing it. That’s kind of tricky.

Render Method

The render method generates the markup we write inside this. After we change the value of our state, the render method will be called. And it will only change the part where we have some changes.

  1. It has a return method where we put our markup. You always have to wrap your markup here with a div or some parent container.
  2. Inside the div, we have a form. It has a textarea with its value of the this.state.message. And the method handleChange (You can also bind your method here) will be called every time there’s a change to our textarea.
  3. Then, we have another component called, Preview. So this component will be a child component of TypeArea. And we passed the value of our this.state.message to this component.

Preview

The second component which is the child component is Preview.

class Preview extends React.Component {
  getRawMarkUp(input) {
    var output = marked(input, {sanitize: true});
    return {
      __html: output
    }
  }
  
  render() {
    return (
      <div className="col-xs-12 col-md-6">
        <p dangerouslySetInnerHTML={this.getRawMarkUp(this.props.message)}></p>
      </div>
    );
  }
}

Method

Go to the Pen Settings. In the JavaScript section, under the ‘Add External JavaScript’, add this: https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js

Our method inside Preview component is getRawMarkUp.

  1. It takes a parameter, input.
  2. Using the Marked library, we’re going to use the marked method passing in our input. And we’re going to get something from this.
  3. And pass it inside return, with the __html. I don’t get it that much but all I know is this is the part where it converts to plain text.
  4.  This method returns that.

Render

  1. We have a paragraph here inside a div.
  2. And in this paragraph, we’re setting the HTML by calling the built-in method, dangerouslySetInnerHTML. It is the replacement of React to innerHTML of the browser DOM.
  3. We pass our user-defined method, getRawMarkUp and pass the value we got from the parent component, TypeArea. Once the parent component passes the state, it becomes a props to the perspective of the child component which is Preview.

So what really happens here is we have to render the TypeArea component which will render our preview component.


ReactDOM.render(<TypeArea />, document.getElementById("root"));

We render our TypeArea component in our div with an id of root.

You can check my whole code here.

And that’s it. That’s how we build a Markdown Previewer with ReactJS.

I hope you understand it.

Still, I recommend customizing and experimenting it to achieve your desired result.

Good luck!

Love,
Eirin

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s