Building a Markdown Previewer with React: A Step-by-Step Guide

React has taken the web development world by storm since its initial release in 2013. Maintained by Facebook, this powerful JavaScript library makes it easy to build interactive, component-based user interfaces. React‘s popularity continues to grow, with over 1,300 contributors and 160,000 GitHub stars.

React Usage Statistics
Source: The State of JavaScript 2020

In this tutorial, we‘ll harness the power of React to build a useful tool: a Markdown previewer. Markdown is a lightweight markup language that allows you to write formatted content using a plain text editor. It‘s commonly used for documentation, blogs, and readme files.

By the end of this guide, you‘ll have a solid understanding of core React concepts and a working Markdown previewer app. Let‘s dive in!

Why Use React?

React offers several key benefits for building complex, data-driven web apps:

  • Component-based architecture: React apps are built with reusable UI components that manage their own state and rendering. This modular approach makes your code more organized and maintainable as projects grow in size.

  • Virtual DOM: React keeps a lightweight virtual representation of the actual DOM in memory. When data changes, React efficiently updates the virtual DOM, then intelligently re-renders only the changed parts of the UI. This provides a major performance boost over manual DOM manipulation.

  • Rich ecosystem: React has a vast collection of third-party libraries, tools, and extensions to enhance your development experience. From state management with Redux to type checking with TypeScript, React integrates well with many other technologies.

  • Active community: With its huge user base and active open-source community, React offers unparalleled resources for learning and support. You can find hundreds of tutorials, articles, and Stack Overflow answers for any React question you might have.

According to the Stack Overflow Developer Survey 2020, React is the second most loved web framework after ASP.NET Core:

Most Loved Web Frameworks
Source: Stack Overflow Developer Survey 2020

Setting Up the Project

To quickly bootstrap a new React project, we‘ll use Create React App. This popular toolchain includes a development server, build scripts, and other configuration out of the box. Make sure you have Node.js installed, then run:

npx create-react-app markdown-previewer
cd markdown-previewer
npm start

Your app will be automatically opened in the browser at http://localhost:3000.

We won‘t need most of the default starter files, so delete all files inside src except index.js and App.js. We‘ll also install the Marked library to parse our Markdown:

npm install marked

Building the Components

React apps are built with functional or class components. Each component returns a piece of JSX (syntactic sugar for function calls to React.createElement) that declaratively describes its part of the UI.

The Editor Component

The editor component will be a <textarea> inside a wrapper <div>. Create a new file src/Editor.js:

import React from ‘react‘;

const Editor = ({ content, onChange }) => {
  return (
    <div className="editor">
      <h2>Markdown Input</h2>
      <textarea 
        id="editor"
        value={content} 
        onChange={onChange}
      />        
    </div>
  );
}

export default Editor;

This stateless functional component accepts the current Markdown content and an onChange callback function as props. When the user types in the <textarea>, the onChange event is triggered and the parent component can update the value.

The Preview Component

The preview component will render the HTML generated from the Markdown input. Create src/Preview.js:

import React from ‘react‘;
import marked from ‘marked‘;

const Preview = ({ content }) => {
  // Parse markdown into HTML
  const html = marked(content);

  return (
    <div className="preview">
      <h2>Rendered Output</h2>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </div>
  );
}

export default Preview;

We use the marked library to parse the content prop into HTML. React‘s dangerouslySetInnerHTML is used to render this HTML. This prop should be used carefully to avoid XSS vulnerabilities, but is safe here since we control the Markdown source.

The App Component

Now let‘s combine the editor and preview components in src/App.js:

import React, { useState } from ‘react‘; 
import Editor from ‘./Editor‘;
import Preview from ‘./Preview‘;
import ‘./App.css‘;

const App = () => {
  // Initialize state with example markdown
  const [markdown, setMarkdown] = useState(
    `# Hello, World! 

This is a **Markdown** previewer built with React.

- Type some Markdown on the left
- See the rendered HTML on the right
    `
  );

  // Handle textarea input
  const handleChange = (e) => {
    setMarkdown(e.target.value);
  }

  return (
    <div className="app">
      <Editor 
        content={markdown} 
        onChange={handleChange} 
      />
      <Preview content={markdown} />
    </div>
  );
}

export default App;

The useState hook allows us to add state to functional components. We initialize the markdown state with a multi-line string containing some example content.

The handleChange function is triggered when the user types in the editor. It extracts the textarea value from the event object and updates the markdown state.

Finally, the <Editor> and <Preview> components are rendered side by side. The current markdown state is passed as their content prop, and handleChange is passed as the onChange prop for the editor.

Styling the App

Our app is fully functional, but let‘s make it look nicer. Add this CSS to src/App.css:

.app {
  display: flex;
}

.editor, .preview {
  width: 50%;
  padding: 20px;
  max-height: 100vh;
  overflow: auto;
}

.editor textarea {
  width: 100%;
  height: 100%;
  resize: none;
  border: none;
  font-family: inherit;
}

.preview {
  border-left: 1px solid #ccc;
}

/* Responsive design */
@media (max-width: 768px) {
  .app {
    flex-direction: column;
  }

  .editor, .preview {
    width: 100%;
    max-height: 50vh;
  }
}

This CSS:

  1. Displays the editor and preview side by side with flexbox
  2. Sets their widths to 50% and adds some padding
  3. Styles the textarea to fill the editor container
  4. Adds a dividing border between the two panes
  5. Makes the layout responsive for mobile screens

Feel free to further customize the styling to your liking.

Extending the Project

There are many ways to enhance our Markdown previewer:

  • Syntax highlighting: Use a library like Prism.js to add code syntax highlighting to code blocks. This greatly improves readability.

  • Markdown shortcuts: Add a toolbar with buttons that insert common Markdown syntax like links, images, and formatting. You can use a library like Markdown-it to support extended syntax.

  • Debounced editing: Implement debouncing so the preview only re-renders after the user has stopped typing for a short delay. This improves performance for large documents.

  • Exporting: Allow the user to export their Markdown or HTML to a file. You can use the fs module in Node.js or the browser‘s Blob API.

  • Persistence: Store the Markdown in the browser‘s local storage so it persists across page refreshes. You can also allow saving multiple documents.

Performance Optimization

As your React app grows, performance can become a concern. Here are some tips to keep things fast:

  • Memoization: Use React.memo or useMemo to avoid unnecessary re-renders of components and expensive calculations. Memoization caches the results of a function call and returns the cached value if the inputs haven‘t changed.

  • Lazy loading: Split your app into smaller chunks and load them on demand with React.lazy and Suspense. This reduces the initial bundle size and speeds up load times.

  • Windowing: For long lists or grids, only render the visible portion of the data. Libraries like react-window and react-virtualized make this efficient.

  • Profiling: Use the React DevTools Profiler to identify and fix performance bottlenecks. It shows you which components re-render and why.

Learning More

We‘ve only scratched the surface of what React can do. To go deeper, consult these resources:

Here‘s what Sophie Alpert, Engineering Manager of the React Core team at Facebook, has to say:

"One of the biggest advantages of using React is that it lets you write your code in a declarative way. Rather than carefully coding how to do things step-by-step, you can describe how things should look in different states, and React takes care of making that happen. It makes your code easier to understand and less error-prone."

By mastering React, you‘ll be able to build impressive web apps and contribute to the thriving React ecosystem. Keep coding, and happy Markdown previewing!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *