DEV Community

Cover image for React without JSX
Utkarsh Mishra
Utkarsh Mishra

Posted on

React without JSX

Let's talk about the pure React. No JSX, No Babel, No parcel or Webpack. Just some JavaScript inside a file.
Let's start with a project. I have created a project directory and I'm going to call it happyBday since I'm going to be building a Happy Birthday app throughout this blog. Then I have created an index.html file and put it into a src/ directory inside of my project folder. Now Inside index.html put:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="./style.css">
  <title>Happy Birthday</title>
</head>

<body>
  <div id="root">Not rendered</div>
  <script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
  <script>
    // code is going to go here
  </script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Now just open this file in your browser.

  • Pretty standard HTML5 document.
  • We're adding a id root in div.
  • We have two script tags.

    • The first is the React library. This library is the interface of how to interact with React; all the methods (except one) will be via this library. It contains no way of rendering itself though; it's just the API.
    • The second library is the rendering layer. Since we're rendering to the browser, we're using React DOM. There are other React libraries like React Native, A-Frame React, React Blessed, and others. We need both script tags. The order is not important.
  • The last script tag is where we're going to put our code. We don't typically do this but I wanted to start as simple as possible. This script tag must come after the other two.

Now in the last script tag, put the following.

const App= () => {
  return React.createElement(
    "div",
    {},
    React.createElement("h1", {}, "Happy Birthday!")
  );
};

ReactDOM.render(React.createElement(App), document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

This is the simplest React app one can build.

  • The first thing i do is make my own component, App. React is all about making components. And then taking those components and making more components out of those.
  • There are two types of components, function components and class components. This is a function component. We'll not going to see class components in this blog.
  • A function component must return markup (which is what React.createElement generates.)
  • Inside of the render function, we cannot modify any sort of state. In functional terms, this function must be pure. You don't know how or when the function will be called so it can't modify any ambient state.
  • React.createElement creates one instance of some component. If you pass it a string, it will create a DOM tag with that as the string. We used h1 and div, those tags are output to the DOM.
  • The second empty object (you can put null too) is attributes we're passing to the tag or component. Whatever we put in this will be output to the element (like id or style.)
  • ReactDOM.render is what takes our rendered App component and puts in the DOM (in our case we're putting it in the root element.)
  • Notice we're using React.createElement with App as a parameter to ReactDOM.render. We need an instance of App to render out. App is a class of components and we need to render one instance of a class. That's what React.createElement does: it makes an instance of a class.

Now let talk a bit more about Components.

Components

Now let's separate that JS code out from a script tag on the DOM to its own script file. Make a new file in your src directory called App.js and cut and paste your code into it.

Modify your code so it looks like:

const Wish= () => {
  return React.createElement("div", {}, [
    React.createElement("h1", {}, "Happy Birthday"),
    React.createElement("h2", {}, "May God bless you!"),
    React.createElement("h2", {}, "~Orio"),
  ]);
};

const App= () => {
  return React.createElement("div", {}, [
    React.createElement("h1", {}, "Happy Birthday!"),
    React.createElement(Wish),
    React.createElement(Wish),
    React.createElement(Wish),
  ]);
};

ReactDOM.render(React.createElement(App), document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

In here:

  • We created a second new component, the Wish component. This component represents a birthday wish. When you have distinct ideas represented as markup, that's a good idea to separate that it into a component like we did here.
  • Since we have a new Wish component, we can use it multiple times! We just use multiple calls to React.createElement.
  • In createElement, the last two parameters are optional. Since Wish has no props or children we can just leave them off.

Let's make it a bit more complicated.

const Wish= (props) => {
  return React.createElement("div", {}, [
    React.createElement("h1", {}, props.name),
    React.createElement("h2", {}, props.message),
    React.createElement("h2", {}, props.gift),
  ]);
};

const App = () => {
  return React.createElement("div", {}, [
    React.createElement("h1", {}, "Happy Birthday!"),
    React.createElement(Wish, {
      name: "Orio",
      message: "Wishing you a day filled with happiness and a year filled with joy.",
      gift: "Floss",
    }),
    React.createElement(Wish, {
      name: "Sudo",
      message: "Sending you smiles for every moment of your special day",
      gift: "Lilies",
    }),
    React.createElement(Wish, { 
      name: "Pie", 
      message: "Hope your special day brings you all that your heart desires", 
      gift: "Rose" }),
  ]);
};

ReactDOM.render(React.createElement(App), document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

Now we have a more flexible component that accepts props from its parent. Props are variables that a parent (App) passes to its children (the instances of Wish.) Now each one can be different! Now that is far more useful than it was since this Wish component can represent not just Orio, but any person. This is the power of React! We can make multiple, re-usable components. We can then use these components to build larger components. This is how React apps are made.

Now let's talk about React Using JSX. Before jumping into JSX let's first separate Wish component in a new file named as Wish.js.

JSX

So far we've been writing React without JSX, something that I don't know anyone that actually does with their apps. Everyone uses JSX. I show you this way so what JSX is actually doing is demystified to you. It doesn't do hardly anything. It just makes your code a bit more readable.

If I write React.createElement("h1", { id: "main-title" }, "Keep Reacting");, what am I actually trying to have rendered out?
<h1 id="main-title">Keep Reacting</h1>, right? What JSX tries to do is to shortcut this translation layer in your brain so you can just write what you mean. Let's convert Wish.js to using JSX. It will look like this:

const Wish= (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
      <h2>{props.message}</h2>
      <h2>{props.gift}</h2>
    </div>
  );
};

export default Wish;
Enter fullscreen mode Exit fullscreen mode

now you know what JSX is doing for you. It's just translating those HTML tags into React.createElement calls. That's it. Really. No more magic here. JSX does nothing else.

  • Notice the strange {props.name} syntax: this is how you output JavaScript expressions in JSX

so now let's go convert App.js.

import ReactDOM from "react-dom";
import Wish from "./Wish";

const App = () => {
  return (
    <div>
      <h1>Happy Birthday!</h1>
      <Wish name="Orio" message="Wishing you a day filled with happiness and a year filled with joy." gift="Floss" />
      <Wish name="Sudo" message="Sending you smiles for every moment of your special day" gift="Lilies" />
      <Wish name="Pie" message="Hope your special day brings you all that your heart desires" gift="Rose" />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode
  • Notice we have Wish as a component. Notice that the W in Wish is capitalized. It must be. If you make it lowercase, it will try to have wish as a web component and not a React component.

Let me know your thoughts in the comments and please mention your views on your favorite JS frameworks.
Thanks for reading!
Connect to me on:

Top comments (1)

Collapse
 
the_yamiteru profile image
Yamiteru

Hmm what do you think about this syntax?

// Shared
import s from "./article.module.css";

type Article = {
  title: string;
  date: string;
  text: string;
};

type Articles = {
  data: Article[];
};

// Functional

const article: Component<Article> = ({ title, date, text }) => 
  box(s.article, [
    title(s.title, title),
    date(s.date, date),
    text(s.text, text)
  ]);

const articles: Component<Articles> = ({ data }) =>
  box(s.articles, [
    map(data, (v) => article(...v))
  ]);

// JSX
const Article = FunctionComponent<Article> = ({ title, date, text }) => (
  <div className={styles.article}>
    <div className={styles.title}>{title}</div>
   <div className={styles.date}>{date}</div>
   <div className={styles.text}>{text}</div>
  </div>
);

const Articles = FunctionComponent<Articles> = ({ data }) => (
  <div className={styles.articles}>
    { data.map((v) => <Article {...v} />) }
  </div>
);
Enter fullscreen mode Exit fullscreen mode