DEV Community

Ahmad Jamaly Rabib
Ahmad Jamaly Rabib

Posted on • Edited on

Learning React : JSX

I am continuing to learn React. It is my second day learning React. If you are only reading this article then you can also visit my experience of learning React on Day 1. πŸ˜„

Let's hope I will get the knowledge to work with React very soon and just not learn then forget. πŸ˜πŸ˜…

So, yesterday we stopped after creating a React element using the React.createElement() method. 😎
Today we will learn about JSX-> JavaScript XML.
JSX looks almost like HTML and it is really easy to use while using React.

JSX and HTML similarity
So I am creating a similar React component for the increment button that we did in vanilla JS yesterday. Let’s update in the increment.js file.

const domContainer = document.querySelector('#root');
const reactIncrement = (
    <div>
        <h1 id="display">0</h1>
        <div>
            <button id="button">Increment +</button>
        </div>
    </div>
);

ReactDOM.render(reactIncrement, domContainer);
Enter fullscreen mode Exit fullscreen mode

Here as we can see I have simply written JSX to render the element in the root div. Let me run the html now. But I got an error in the console. 😞

Uncaught SyntaxError: Unexpected token '<' (at increment.js)
Enter fullscreen mode Exit fullscreen mode

The reason for this error is Javascript doesn't recognize the JSX tags we have used. Even though I renamed the increment.js file to increment.jsx (As I am now using JSX :wink:) it didn't work. 😟

Using JSX

To get rid of this situation at last we found a way. We need to use a transpiler.
Transpilers are tools that convert one programming language into another language. 😲
In this case of React we will use Babel as a Transpiler. Babel will convert our JSX codes to vanilla JS.
There are also other use cases of Babel to help us coding without worring about the compatibility of different browsers. 😍

Here I checked my JSX code in babel.io website how it converted our JSX code to JS.

So let's go to babel website -> setup -> In the browser link and copy the babel script to our html file. Also let's add the increment.js script type to "text/babel".

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel" src="./increment.jsx"></script>

Enter fullscreen mode Exit fullscreen mode

Now when we run the html in the browser we can see that the counter button and display is appearing and there is no console error.

Issue Fixed

  • Let's add the increment functionality in the JS file. Let's first create an Increment method.
const Increment = () => {};
Enter fullscreen mode Exit fullscreen mode
  • Now let's copy the JSX codes we wrote before in the increment.js file inside the function, so that this Increment method returns that JSX code.
const Increment = () => {
  return (
    <div>
        <h1 id="display">0</h1>
        <div>
            <button id="button">Increment +</button>
        </div>
    </div>
  );
}
// Render Increment
ReactDOM.render(<Increment />, domContainer);
Enter fullscreen mode Exit fullscreen mode

We are still viewing the same button and display with no functionality update till now. πŸ˜’
Display Button
Now let's copy the increment functionality from the vanilla JS code that we wrote yesterday in our increment.js file.

const domContainer = document.querySelector('#root');
const Increment = () => {
  return (
    <div>
        <h1 id="display">0</h1>
        <div>
            <button id="button">Increment +</button>
        </div>
    </div>
  );
}

let number = 0;

let button = document.querySelector('#button');
let display = document.querySelector('#display');

button.addEventListener('click', () => {
    number++;
    display.textContent = number;
});

ReactDOM.render(<Increment />, domContainer);
Enter fullscreen mode Exit fullscreen mode

Did we get what we wanted? No! 😞
I got a console error after copying this.

Error in Console
Let's fix this issue now.

Button null

So from the console error we found that the button is null. That means the button is not defined. So it seems we are calling the button event even before the button is initialized and rendered by calling the Increment function.

So now let's render the elements first before calling the button.

ReactDOM.render(<Increment />, domContainer);

let number = 0;

let button = document.querySelector('#button');
let display = document.querySelector('#display');

button.addEventListener('click', () => {
    number++;
    display.textContent = number;
});
Enter fullscreen mode Exit fullscreen mode

It works now!

Incrementing number
But does it solve the problem? Can we use multiple components this way? Let's say we want two counters. Will it work? This is the reason we are working with React right?
The answer is no. 😭 We still haven't achieved what we want.

I tried adding the Increment component multiple times in the render.

ReactDOM.render(<><Increment /><Increment /><Increment /></>, domContainer);
Enter fullscreen mode Exit fullscreen mode

The functionality should work independently, but it didn't.

All component not working
In the above image we saw that only the first component is working but the others aren't.

The main reason for the above issue is that we aren't doing things in React way. Now let's do our coding in the React way. πŸ’ͺ

React tells us that we shouldn't manipulate DOM. But in our code we are still selecting DOM components, creating counter variable then updating counter using DOM manipulation. Which is actually prohibited in React.

So let's first remove our button and display counter functionality code.

To achieve this functionality using React we need to use State.

State is a built-in React object which is used to contain data or information about the component.

So in our counter functionality what is the state? This is our number variable. Because only this data is changing and based on this our components' content is changing.

Now let's use this knowledge to create a State inside the Increment function.

const Increment = () => {
    const counter = React.useState(0);
    ...
};
Enter fullscreen mode Exit fullscreen mode

So what did I do there? I am using useState and setting an initial value which is 0 in this case. Let's do a console.log(counter).

React State
So, it returns an array which has two elements.
The first one is the value we set for the state and the second one is a function.

This function actually helps us by returning an updated value based on the parameter we will pass to the function.

So, this function updates the state and triggers a re-render of our component.
This can be used like this:

const [state, setState] = React.useState(initialValue);
Enter fullscreen mode Exit fullscreen mode

Let's update our Increment method now.

const [counter, setCounter] = React.useState(0);
Enter fullscreen mode Exit fullscreen mode

Here we created the setCounter function which we will call during the button click event. So our updated button will be:

<button id="button" onClick={ () => setCounter(counter + 1) }>Increment +</button>
Enter fullscreen mode Exit fullscreen mode

I am using JSX. The onClick function isn't the same as normal HTML. Couldn't find the issue the first time. Also I am using curly braces {} not quotation " like we used to use in HTML. Found these differences in JSX for now. I need to get used to it πŸ˜†

To show that counter in the display we will update our display area where we will bind the counter variable inside h1.

<h1 id="display">{ counter }</h1>
Enter fullscreen mode Exit fullscreen mode

So after the updates I have now successfully created a React component, which is reusable and can be used several times. And most interestingly I can call this multiple times and can have multiple independent components without writing more codes. πŸ˜…

This is my JS code now.

const Increment = () => {
    const [counter, setCounter] = React.useState(0);
    return (
        <div>
            <h1 id="display">{ counter }</h1>
            <div>
                <button id="button" onClick={ () => setCounter(counter + 1) }>Increment +</button>
            </div>
        </div>
    );
};

ReactDOM.render(<div className="container"><Increment /><Increment /><Increment /></div>, domContainer);

Enter fullscreen mode Exit fullscreen mode

I have called the Increment method 3 times and it is now working fine!

Success!

Here is the github link for the two projects I have worked till now.

This is all for today. I will try to learn about React DOM tomorrow. Hopefully write something from that. Till then bye! πŸ‘‹

Top comments (0)