JSX


Previous post: Anatomy of a React Component 
Next section: The Basics


JSX

When working with React, you'll very quickly come across JSX, which looks a bit like HTML, but also has bits of JavaScript in there (or JavaScript with HTML mixed in, depending on how you look at it).  So what is it?  The React docs describe JSX as a 'syntax extension for JavaScript' - in other words, it's fundamentally JavaScript, but it allows you to add HTML to it (so, JavaScript with HTML mixed in, I guess). It was designed to be used with React, and it lets us describe to the browser what our UI should look like and how it should behave.  You don't have to use it to use React, but it makes things much easier if you do.

Essentially, JSX produces React elements which describe both what the component should look like, and what the component should do.

We've already seen examples of basic JSX in the previous tutorial, for instance:

    return <h1>Hello world!</h1>

In this case, <h1>Hello world!</h1> is an example of a React element (this one happens to be all appearance and no logic).


How Does It Work?

HTML tags like <h1>...</h1> and <p>...</p> are examples of HTML elements, which the browser can render for us, with a bit of static text (eg <h1>Hello</h1>).  With JSX, we can go further - we can render a variable in there too.  For example, we can declare a variable, and then use it to create an element:

    const myHeading = "Hello World";
    const element = <h1>{myHeading}</h1>;

The curly brackets are all that's needed to slot JavaScript in.

We can return elements from functions:

    const sayHello = (name) => { 
        return <h1>Hello {name}</h1>;
    }

so

    sayHello('Jim');

would return

    <h1>Hello Jim</h1>

 

We can also use if statements:

    const sayHello = (name) => {
        if (name) {
            return <h1>Hello {name}</h1>
        } else {
            return <h4>Sorry, I don't know you</h4>
        }
    }

 

loops:

    If we have an array of names called nameList:
    ['Jim', 'Bob', 'Mary', 'Cynthia']

    then we can say "Hello" to everyone at once by looping over the list: 

    const sayHello = (nameList) => { 
        return ( 
            <> 
                <h1>Hello</h1> 
                { 
                    nameList.map((name) => { 
                        return <h4>{name}</h4> 
                    })
                }
            </>
        )
    }

 

and JavaScript's ternary operator:

    const sayHello = (name) => <h1>{ 
        name ? name : "We haven't met" 
    }</h1>

    (this will render name if it has been given, and "We haven't met" if it's null).

as well as many other JavaScript functions.

NOTE: When we accept any kind of user input, there is always a risk that the user will attempt something malicious.  For example, if they are asked to enter their name, they might instead enter code which would wipe out our database. If we're not careful, the browser will attempt to show the 'name', realise that it's code, and execute it... bye bye database.  Thankfully, React handles this for us.  Anything embedded in JSX is 'escaped' before being rendered, which means that our browser will see it as regular text, and not as a command. So it's safe to embed anything entered by the user into JSX and to render it on the screen.

 

Attributes

JSX can also produce elements which have attributes.  These can be specified by a string literal, or a JavaScript expression.  For instance:

    // This value for href is a string, so we use double quotes 
    const element = <a href="https://reactjs.org" />


    // This value for href is a JS expression,
    // so we use curly brackets 
    const element2 = <a href={page.pageUrl} /> 


Children

JSX tags can contain children:

    <div>
        <h1>Hello Again</h1>
        <h2>Welcome</h2>
    </div>

 

Empty Tags

If a tag has no content (only attributes) then it can be closed immediately with />:

    <a href="https://reactjs.org" />


Rendering JSX

Once we have an element, we need to show it on the screen.  By creating our app with create-react-app, this is already set up for us.  Take a look in index.js again, and you'll see this section (ignore the lines that mention React.StrictMode):

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<App />);

This is where the rendering happens.  The first line finds the HTML element with id 'root', and gets it ready to add some content. Then, the render function adds the content to root. As long as App returns a single JSX element, then that JSX element will be rendered in root.  Of course, that single element can have lots of child elements, and each of those can have child elements, and so on.

An important point here is that each component must return a single element.  That element may contain other elements, but they must all be wrapped up together.  So this is not valid:

    return ( // NOT VALID, because it is made up of 2 elements
      <h1>Item 1</h1>
      <h1>Item 2</h1>
    )

but this is:

    // VALID, because we've wrapped both elements in <> ... </> 
    return (
        <>
            <h1>Item 1</h1>
            <h1>Item 2</h1>
        </>
    )

NOTE: we don't have to use <> to wrap the elements; we can use anything that produces valid HTML, such as <span> or <div>

It's like a flight which allows each passenger to have 1 bag - you can't take a bag of apples and a bag of oranges, but if you put them both into another bag, you're fine.

Summary

So:

1. Every React component must return a JSX element, even if it's just '<></>'.

2. Every React component must return a single JSX element; if you need to return multiple elements, you need to wrap them in a single tag




Next section: The Basics

Comments