Are we allowed to use JSX outside of return in functional components?

Viewed 919

I have a quick question because I am a bit confused with JSX in functional components.

I am doing a small project to explore more complex uses of useState() and in the final portion of this challenge, you have to render the Contacts you type into an input form.

This is my code:

import React, { useState } from "react";

function App() {
  const [inputData, setInputData] = useState({ firstName: "", lastName: "" });
  const [contactsData, setContactsData] = useState([]);

  function handleChange(event) {
    const { name, value } = event.target;
    setInputData((prevData) => {
      return {
        ...prevData,
        // will copy over all properties from the previous input data and then replace whichever one we are currently working on with the updated value
        [name]: value,
      };
    });
  }

  function handleSubmit(event) {
    event.preventDefault();
    setContactsData((prevContacts) => [...prevContacts, inputData]);
  }

  const contacts = contactsData.map((contact) => (
    <h2 key={contact.firstName + contact.lastName}>
      {contact.firstName} {contact.lastName}
    </h2>
  ));

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input
          placeholder="First Name"
          name="firstName"
          value={inputData.firstName}
          onChange={handleChange}
        />
        <input
          placeholder="Last Name"
          name="lastName"
          value={inputData.lastName}
          onChange={handleChange}
        />
        <br />
        <button>Add contact</button>
      </form>
      {contacts}
    </>
  );
}

export default App;

My questions is why does const contacts have JSX outside of the return? I thought all JSX had to be within the return?

When I try to input the contacts without an outside const variable, I get a reference Error?

Thanks!

1 Answers

You can put JSX anywhere you like. While JSX looks kind of like html, it actually gets transformed into a series of calls to React.createElement. For example, the piece of code you're wondering about gets transpiled into this:

const contacts = contactsData.map(contact => {
  return React.createElement(
    "h2", 
    { key: contact.firstName + contact.lastName }, 
    contact.firstName,
    " ",
    contact.lastName
  );
});

Each call to React.createElement returns an object describing what to render to that part of the page. You can do anything you like with these objects. Most commonly you'll return them from a function (as you're used to), but they can also be assigned to variables as is happening here.

So if you did this as part of the return statement, you'd be making an array in line, and then passing that as one of the parameters to a call to React.createElement. With the code you actually wrote, you're making that same array, just doing it up front and saving it to a variable, and then passing it to React.createElement later on.

Related