React components
Learn the basics of creating DOM elements using JSX and React components
React makes dealing with the DOM in JavaScript more like writing HTML. It helps package up elements into "components" so you can divide your UI up into reusable pieces.
React elements
Interacting with the DOM can be a frustrating experience. It requires lots of awkward lines of code where you tell the browser exactly how to create an element with the right properties.
Even if we create our own function to handle some of the repetitive parts it's a little hard to read:
This is frustrating because there is a simpler, more declarative way to create elements: HTML.
Unfortunately we can't use HTML inside JavaScript files. HTML can't create elements dynamically as a user interacts with our app. This is where React comes in:
This variable is a React element. It's created using a special syntax called JSX that lets us write HTML-like elements within our JavaScript.
The example above will be transformed into this normal JS:
This function call returns an object that describes your element:
React builds up one big tree structure of all these element objects that represents your entire app. It then uses this tree to create the actual DOM elements for you. (This is called the virtual DOM, but you don't need to worry about that right now)
It can be helpful to remember that the HTML-like syntax is really normal function calls that return objects.
Templating dynamic values
JSX supports inserting dynamic values into your elements. It uses a similar syntax to JS template literals: anything inside curly brackets will be evaluated as a JS expression, and the result will be rendered. For example:
You can do all kinds of JS stuff inside the curly brackets, like referencing other variables, or conditional expressions.
Note on expressions
You can put any valid JS expression inside the curly brackets. An expression is code that resolves to a value. I.e. you can assign it to a variable. These are all valid expressions:
This is not a valid expression:
if
blocks are statements, not expressions. The main impact of this is that you have to use ternaries instead of if
statements inside JSX.
React components
React elements aren't very useful on their own. They're just static objects. To build an interface we need something reusable and dynamic, like functions.
A React component is a function that returns a React element.
Valid elements
A React element can be a JSX element, or a string, number, boolean or array of JSX elements. Returning null
, undefined
, false
or ""
(empty string) will cause your component to render nothing.
Composing components
Components are useful because JSX allows us to compose them together just like HTML elements. We can use our Title
component as JSX within another component. It's like making your own custom HTML tags.
When we use a component in JSX (<Title />
) React will find the corresponding Title
function, call it, and use whatever element it returns.
Customising components
A component where everything is hard-coded isn't very useful. It will always return the exact same thing, so there's almost no point being a function. Functions are most useful when they take arguments. Passing different arguments lets us change what the function returns each time we call it.
JSX supports passing arguments to your components. It does this using the same syntax as HTML:
React component functions only ever receive one argument: an object containing all of the arguments passed to it. React will gather up any key="value"
arguments from the JSX and create this object.
This object is commonly named "props" (short for properties). Using an object like this means you don't have to worry the order of arguments. So in this case our Title
function will receive a single argument: an object with a "name" property.
You can use these props within your components to customise them. For example we can interpolate them into our JSX to change the rendered HTML:
Now we can re-use our Title
component to render different DOM elements:
Non-string props
Since JSX is JavaScript it supports passing any valid JS expression to your components, not just strings. To pass JS values as props you use curly brackets, just like interpolating expressions inside tags.
Children
It would be nice if we could nest our components just like HTML. Right now this won't work, since we hard-coded the text inside our <h1>
:
JSX supports a special prop to achieve this: children
. Whatever value you put between JSX tags will be passed to the component function as a prop named children
. You can then access and use it exactly like any other prop.
Now this JSX will work as we expect:
This is quite powerful, as you can now nest your components to build up more complex DOM elements.
Rendering to the page
You may be wondering how we get these React components to actually show up on the page.
React consists of two libraries—the main React
library and a specific ReactDOM
library for rendering to the DOM (since React can also to render Virtual Reality or Native mobile apps).
We use the ReactDOM.render()
function to render a component to the DOM. It takes an element as the first argument and a DOM node as the second.
It's common practice to have a single top-level App
component that contains all the rest of the UI.
Challenge
Time to create some components! Open up challenge.html
in your editor. You should see the components we created above. Open this file in your browser too to see the components rendered to the page.
Create a new component called Card
. It should take 3 props: title
, image
and children
, that render into h2
, img
and p
elements respectively.
Replace the p
in the App
component with a Card
. Pass whatever you like as the 3 props (although here's an image URL you can use: https://source.unsplash.com/400x300/?burger
).
Last updated