What are React Elements?
When we created our React component ProductList earlier, we used JSX to describe its elements. But what exactly are these React elements? Simply put, React elements are JavaScript objects that represent the different parts of your user interface. They're the building blocks of your UI, and they can be thought of as a virtual representation of the DOM.
Think of it this way: when you write HTML, you describe pages to your browser using tags like <div> or <p>. The browser then takes these tags and turns them into actual elements in the DOM. Similarly, when you use React, you create elements that represent different parts of your UI. These elements can contain other elements, just like how a <div> element might contain a <p> element.
To create a React element, you can use the React.createElement method, like this:
var boldElement = React.createElement('b');
This code creates a React element that represents a <b> (bold) element. You can then pass this element to the ReactDOM.render method to render it in the DOM.
So, when we say that JSX "creates elements," we mean that it allows you to describe these virtual elements using a syntax that's similar to HTML. This makes it easy to define your UI components and their relationships with each other.
Why Use React Elements?
When you’re working with React in a browser, React can mount the described views in the browser’s DOM (Document Object Model) and automatically update what needs to be updated whenever the original state changes. This is because every component in a React application has a private state that may change over time, and React will take care of updating the component's view when its state changes.
JSX allows you to create React elements that can then be used to describe views based on some state. You can think of JSX as an enhancement of JavaScript to allow for syntax that looks like HTML. For example, we can represent an email input field interface with JSX:
<form>
<label htmlFor="email">Email:</label>
<input type="email" id="email" className="form-control" />
</form>
JSX is completely optional and not required to use React; you can write React in plain JavaScript.
Understanding the JSX
JSX is an abstraction that allows you to write HTML-like syntax in your JavaScript code. This enables you to build React components that look like standard HTML markup.
When we created our React element earlier, we used React.createElement like this:
var boldElement = React.createElement('b', null, "Text (as a string)");
This works fine for small components, but if we had many nested components, the syntax could get messy quickly. Our DOM is hierarchical and our React component tree is hierarchical as well.
JSX creates elements that can be used to describe pages to our browser. We can think of it this way: to describe pages to our browser, we write HTML; the HTML is parsed by the browser to create HTML elements which become the DOM.
Creating Basic Elements
JSX is an abstraction that allows you to write HTML-like syntax in your JavaScript code. To describe elements with JSX, start by thinking about the initial state of your UI. In this case, we have a Row component and a Cell component. We need to render this.props.rows Row instances, and within each row, we need to render this.props.columns Cell instances.
This sounds like a nested loop, but we can't use regular loops in JSX. Instead, prepare a data matrix (rows × columns) and then map that matrix into Rows and Cells components inside the returned JSX. This is a more declarative way of rendering the grid and will make things easier going forward.
For example:
function Grid({ rows, columns }) {
return (
<div>
{rows.map((row, i) => (
<Row key={i}>
{columns.map((column, j) => (
<Cell key={j} />
))}
</Row>
)}
</div>
);
}
By using a data matrix and mapping it to JSX elements, we can create complex UI components without resorting to imperative code.
Working with Text and Images
When it comes to rendering text and images in React, we have several options available. One of the most straightforward ways is by using JSX, which allows us to create JavaScript objects that represent HTML nodes.
Let's take a look at an example of creating a normal element: React.createElement("a", { href: "/" }, "Home");. As you can see, we're passing the type of element ("a"), its props ({ href: "/" }), and the text content ("Home").
To create a parent-child relation, we can use the arguments of the React.createElement function. For instance, to make an image clickable, we would do something like this:
React.createElement("a", { href: "/" },
React.createElement("img", { src: "logo.png" })
);
This is how we represent a tree with React. Under the hood, React will eventually generate HTML strings from these JavaScript objects and concatenate them together.
Having the power to write HTML with JavaScript brings several benefits. We can manipulate data using JavaScript, which makes it easier to update our user interface. This approach also allows us to avoid directly manipulating the DOM, which can be expensive.
Handling User Input
Now that we've shown that we can get user-submitted names, we can begin to use this information to change the app's state and UI. The goal is to show a list with all of the names that the user has entered. React makes this easy by allowing us to create an array in our state to hold the names and populate a list using that array in our render() method.
To do this, we'll make a few additions to our component. First, we'll create a names array in our state. In React, when we're using ES6 component classes, we can set the initial value of our state object by defining a property of state.
Here's what that looks like:
state = { names: [] };
This sets the initial value of our names array to an empty array.
Using Conditional Rendering
You can conditionally show or hide elements in React by using JavaScript conditional statements. One way to do this is by using short circuiting with &&. For example:
<p>{displayAction && <p>Some text</p>}</p>
In this example, the displayAction variable is expected to be a boolean value. If it's true, the <p> element will be rendered; otherwise, it won't. This approach ensures that the element only exists in the final markup if the condition is met.
You can also use this technique to conditionally show or hide elements based on other information, such as state or props passed from a parent component. For instance:
const renderAdminMenu = () => {
return (<MenuLink to="/users">User accounts</MenuLink>);
};
const userLevel = this.props.userLevel;
return (
<ul>
<li>Menu</li>
{userLevel === 'admin' && renderAdminMenu()}
</ul>
);
In this example, the renderAdminMenu function is only called and rendered if the userLevel is set to 'admin'.
Managing Element State
When managing state in React components, you can use props to store data. Props are immutable, which means that once they're passed into a component, their value cannot be changed. This is important because it ensures that your application remains predictable and easy to reason about.
Here's an example of using props to manage element state:
function Product({ product }) {
return (
<div>
<h2>{product.name}</h2>
<p>Price: {product.price}</p>
</div>
);
}
const products = [
{ name: 'Product A', price: 10.99 },
{ name: 'Product B', price: 7.99 },
];
ReactDOM.render(
<React.Fragment>
{products.map((product) => (
<Product key={product.name} product={product} />
))}
</React.Fragment>,
document.getElementById('root')
);
In this example, the Product component receives a prop called product, which contains information about each product. The component uses this prop to render dynamic content.
When you need to manage state in React components, using props is often a good starting point.
Common Mistakes to Avoid
When rendering elements in React, it's easy to make mistakes that can lead to unexpected behavior or errors. One common mistake is returning multiple elements without wrapping them in a single element. For example:
function App() {
return (
<h1>Hello, World</h1>
<p>I am writing JSX</p>
);
}
In this case, you are returning two elements: <h1> and <p>. The fix is a small code change. Surround the code with an empty tag: <> </> . This will create a single element that React can work with.
Another mistake is not using JSX correctly. For example:
function App() {
return <p>Hello, World</p>;
}
In this case, you are returning a single <p> element, but the code is not wrapped in curly braces `{}``. The correct way to write this code is:
function App() {
return { <p>Hello, World</p>; };
}
These mistakes can be avoided by following best practices and using JSX correctly. By doing so, you can ensure that your React components are rendered correctly and behave as expected.