Engineering

React is just JavaScript

No items found.

Many people starting out get overwhelmed by all the things happening in the React ecosystem. There’s this idea that what happens in React is magic and that getting started with React is super complicated unless you use tools like create-react-app.

And honestly, it’s not as widely documented that you only need 5 minutes to actually inject React into your page. Dan Abramov has been trying to raise awareness to this and he’s been doing an amazing job, so taking from his idea let’s make you believe the 5 minutes statement.

But how do I inject React into my application?

Well, first step is finding the files to insert, and these can be found at UNPKG. This is like a giant CDN of all the awesome libraries and frameworks around the world.

If you go to the URL https://unpkg.com/react@16/ you will see all the contents React has and in there you have two folders:

The folder UMD(Universal Module Definition) is the one we want as this one is understood by the browser without any bundler.

You need to also go to https://unpkg.com/react-dom@16/ to get the URL of development version of React Dom as we also need this library to make our project work.

The two links are:

Curious about the cjs folder?

The cjs folder is for use with NPM and the one used when you import react with npm and cjs means CommonJS and is also what is used is used in node for example.

Creating our HTML file

To start we need an initial HTML file. I use VSCode, so here, to create a simple HTML file you just need to type !and then tab and you will have a starter file to insert the two links with script tags. Mine looks like this:

<!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">
  <title>React Starter</title>
</head>
<body>
  <main id="app"></main>

  <!-- Note: when deploying, replace "development.js" with "production.min.js". -->
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<script>
  // This is where our react code will go
</script>
</body>
</html>

Let’s now write some react code!

What is JSX?

JSX (JavaScript XML) may look confusing and magical but in reality it’s just some syntax sugar over the React.createElement function. If we don't want any type of npm or webpack magic we can just use this function that has the same effect so let's take a look at it.

React Create Element Parameters

Knowing this, we can create a simple div that has some text inside and a class to be styled in CSS, like so:

<script>
    function wrapper() {
      return React.createElement(
        'div',
        { className: 'wrapper' },
        'Hello From React'
      );
    }
</script>

If you reload the page, nothing will happen. This is where react-dom comes into play because react itself can be rendered into a lot of places, like native apps for iOS and Android, TV's, PDF and really anything you set your mind to.

react-dom is the library we want in order to render it into the web and then we need the ReactDOM.render function. This function takes two arguments:

  • The element we want to render. In this case, that’s is our wrapper function
  • Where we want to render it to. In this function you can render it straight into the body but I would always advise to create a new element like a main and render it there. To get this element we will use document.querySelector and pass it our #app.

In code this would look something like:

<script>
    function wrapper() {
      return React.createElement(
        'div',
        { className: 'wrapper' },
        'Hello From React'
      );
    }

  var container = document.querySelector('#app');
  ReactDOM.render(
     React.createElement(wrapper),
    container
  );
</script>

If you reload the page, you can see our wrapper but it doesn’t really look nice so let’s add some CSS to it:

html,
body,
#app {
  margin: 0;
  padding: 0;
  background: #001f3f;
  height: 100%;
  color: white;
}

.wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  font-family: Avenir, Arial, Helvetica, sans-serif;
  font-size: 60px;
  align-items: center;
  justify-content: center;
}
view raw

And now you should see something like this when you open your index.html in your browser:

So we got the basics of showing an element and now let’s get into some more interactivity by using React’s Component State.

Creating some interaction

In this part we are going to create the best App ever. We will get a dog photo from https://dog.ceo/api/breed/akita/images/random, show it on the page, and also add a button to refetch another dog photo. Trust me it's going to be great!

The first thing we need to do is to make our function be a React.Component. The main difference for us is that these Components can hold state and the functions can't.

The state contains data specific to this component that may change over time. The state is user-defined, and it should be a plain JavaScript object. — via reactjs.org

We should also consider that if we attach this state to a rendered element, this element will update once the state changes.

For our use case we will need am image property in our state that will have the source for our image. So our Wrapper should look something like:

class Wrapper extends React.Component {
  constructor(props) {
    super(props)
    this.state = { image: null }
  }

  render() {
    return React.createElement(
      'div',
      { className: 'wrapper' },
      'there will a puppy here 😍'
    )
  }
}

Wow! So this changed a lot so let’s through what is going on:

We now have a class instead of a simple function, you can read more about classes on the Mozilla Developer Docs. We also extend out of React.Component, which means that React.Component is our parent class and we inherit methods from it.

The constructor method is a special method for creating and initialising an object created with a class. There can only be one special method with the name “constructor” in a class. A SyntaxError will be thrown if the class contains more than one occurrence of a constructor method. - via developer.mozilla.org

A constructor can use the super keyword to call the constructor of the parent class.

After creating our base class we set the initial state that will be changed with this.state = { image: null }; the reason this is null in the start is because we don't have an image yet. Then in the render function we return the HTML element react will create for us.

Next step is creating the image tag that will have our awesome puppy:

function Img(props) {
  return React.createElement('img', {
    src: props.source
  })
}

We have seen this pattern before when creating our Wrapper component. The only thing we changed here from our Wrapper component is that we now receive an argument with all the props passed to the element. In the props object there is a parameter called source and set that as the src attribute of the image. We also don't pass any children as images don't really have any elements inside them.

Now for the button we do something similar:

function Button(props) {
  return React.createElement(
    'button',
    { onClick: props.getImage },
    'Get a new puppy'
  )
}

Here we receive the a function that will be called when this button is clicked and will get another random puppy.

Putting all of this together

We have all the pieces and let’s now get this all working together in our Wrapper component by attaching these two elements to the Wrapper class and it's state.

To place these two elements as children of the Wrapper, we need to pass them as the arguments of the React.createElement function. Any argument after the second one will be seen as a children by React.

Our Wrapper will look something like:

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

  render() {
    return React.createElement(
      'div',
      { className: 'wrapper' },
      React.createElement(Img, { source: this.state.image }),
      React.createElement(Button, { getImage: this.getImage })
    )
  }
}

Now it’s time we actually fetch the image and for that we will use the fetch api provided by most modern browsers.

Let’s do that in a separate function and call it when the component mounts on the page:

class Wrapper extends React.Component {
  constructor(props) {
    super(props)
    this.state = { image: null }

    this.getImage = this.getImage.bind(this)
  }

  getImage() {
    return fetch('https://dog.ceo/api/breed/akita/images/random') // Get The image
      .then(rsp => rsp.json()) // Transform the response to JSON
      .then(data =>
        this.setState({
          image: data.message // Set the state.image equal to response of the api
        })
      )
  }

  componentDidMount() {
    // https://reactjs.org/docs/react-component.html#componentdidmount
    this.getImage()
  }

  render() {
    return React.createElement(
      'div',
      { className: 'wrapper' },
      React.createElement(Img, { source: this.state.image }),
      React.createElement(Button, { getImage: this.getImage })
    )
  }
}

First thing we did was create a getImage function and in that function we get the image. When we got it we called setState, which is how you change the state of a component in React. Assigning the state to a new object won't work because React won't re-render the component.

In componentDidMount we called the getImage function we just created and this will populate this.state.image. That we can pass it to the img element and show our new puppy. We also pass our getImage function to the button so that the user can request a new puppy.

The bind in the constructor is done because functions have their own scope and not the scope of the class it's a part of. When we have a function like this, the value of this is no longer the class methods like setState but it's instead the own function. The this keyword is confusing when you first hear about so you can read more about it in the Mozilla Developer Docs.

We can do two things, we can bind it manually with this.getImage = this.getImage.bind(this) and this will change the scope to be the class. Or we can use arrow functions as these ones have no scope. In this case, for clarity, I decided to go with the first one.

You can see a live version of our awesome website here: https://react-no-jsx.now.sh

Also the code here: https://gist.github.com/SaraVieira/c99fd3ff7177b86c14209df92483f784

I want some magic!

So you want some JSX ah?

I like you! You live on the edge! I would say that to start you can go on the Babel’s online playground and play with it a bit. Once you understand it and want to apply to this exercise without much setup you can follow this guide by the react team.

After this you can start playing on codesandbox that offers the whole environment online.

Adding JSX to a project is just like adding a CSS preprocessor. It’s a single command you can run to convert all your script tags. You don’t need to install webpack or similar tools.

Conclusion

Hope this cleared some of the magic React sometimes feels to have and got you excited about it. Even if you already know React I hope this has taught you some new fundamentals you might not be aware of.

Go and build dope stuff with React! ⚛️

Thank you to Dan Abramov for bringing this to light!

React is just JavaScript
was originally published in YLD Blog on Medium.
Share this article: