React is a JavaScript library for building user interfaces. This guide introduces you to the core concepts of React that you’ll use regularly.
What You Will Learn
- Creating and nesting components
- Adding markup and styles using JSX
- Displaying dynamic data in components
- Implementing conditional rendering and lists
- Handling user events and updating the UI
- Sharing data effectively between components
Creating and Nesting Components
React applications are built from reusable units called components. Think of components as independent, self-contained pieces of your user interface (UI). They manage their own logic and appearance, ranging in size from small buttons to entire pages.
In React, components are essentially JavaScript functions that return markup, describing what should be displayed on the screen.
function MyButton() {
return (
<button>I'm a button</button>
);
}
This code snippet defines a simple component named MyButton
. To use this component within another component, you can nest it like this:
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
Here, MyButton
is nested inside the MyApp
component. A key thing to notice is that component names in React always start with a capital letter (MyButton
), which distinguishes them from standard HTML tags (which are lowercase like div
, button
, etc.).
Let’s see this in action:
function MyButton() {
return (
<button>I'm a button</button>
);
}
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
The export default
keyword designates MyApp
as the main component of this file. For deeper understanding of JavaScript syntax like export default
, MDN (Mozilla Developer Network) and javascript.info are excellent resources.
Writing Markup with JSX
The syntax used for markup in the previous examples is called JSX. JSX is an extension to JavaScript that allows you to write HTML-like syntax directly within your JavaScript code. While JSX is optional in React, it’s widely adopted due to its convenience and readability, and is supported by all recommended React development tools.
JSX has stricter rules compared to HTML. For instance, tags like <br />
must be explicitly closed. Also, a component in JSX cannot return multiple top-level tags directly. They must be enclosed within a single parent element, such as a <div>...</div>
or an empty fragment <>...</>
:
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}
If you need to convert existing HTML code to JSX, online converters are readily available to automate the process.
Adding Styles in React
In React, you apply CSS classes using the className
attribute. This works identically to the standard HTML class
attribute:
<img className="avatar" />
You then define the CSS rules for the .avatar
class in a separate CSS file:
/* In your CSS file */
.avatar {
border-radius: 50%;
}
React offers flexibility in how you incorporate CSS files. A common approach is to include a <link>
tag in your HTML file. If you’re using build tools or frameworks, refer to their specific documentation for instructions on integrating CSS files into your project.
Displaying Data Dynamically
JSX’s power comes from its ability to seamlessly blend markup with JavaScript. Curly braces {}
in JSX act as an “escape hatch” back into JavaScript, letting you embed variables and expressions directly into your markup. For example, to display a user’s name stored in a variable user.name
:
return (
<h1>
{user.name}
</h1>
);
You can also embed JavaScript expressions within JSX attributes, but remember to use curly braces {}
instead of quotation marks ""
. For instance, className="avatar"
sets the CSS class to the string “avatar”, while src={user.imageUrl}
accesses the JavaScript variable user.imageUrl
and uses its value for the src
attribute:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
JSX curly braces can accommodate more complex JavaScript expressions, including string concatenation and function calls.
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};
export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}
In this example, style={{}}
is standard JavaScript syntax – an object within JSX curly braces, used to apply inline styles dynamically based on JavaScript variables.
Conditional Rendering
React leverages JavaScript’s conditional logic for rendering different content based on conditions. You can use standard JavaScript constructs like if
statements to conditionally render JSX:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
For more concise conditional rendering, you can use the ternary operator ?
. It works directly within JSX:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
When you only need to render something if a condition is true (and nothing otherwise), the logical AND operator &&
provides a shorter syntax:
<div>
{isLoggedIn && <AdminPanel />}
</div>
These techniques also apply to conditionally setting attributes. If you’re new to these JavaScript conditional patterns, starting with if...else
statements is perfectly acceptable.
Rendering Lists
To display lists of items in React, you’ll typically use JavaScript’s array methods like for
loops or the map()
function.
Consider an array of product objects:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
Within a component, use map()
to transform this array of products into an array of JSX list items:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
The key
attribute is crucial here. For each item in a list, you should provide a unique key
– a string or number that identifies that item among its siblings. Database IDs are often ideal keys. React uses these keys to efficiently update and re-render lists when items are added, removed, or reordered.
const products = [
{ title: 'Cabbage', isFruit: false, id: 1 },
{ title: 'Garlic', isFruit: false, id: 2 },
{ title: 'Apple', isFruit: true, id: 3 },
];
export default function ShoppingList() {
const listItems = products.map(product =>
<li key={product.id}
style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
}
Responding to Events
React allows you to make your UI interactive by responding to user events. You can define event handler functions within your components to handle events like clicks, form submissions, and more.
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
Notice that in onClick={handleClick}
, we pass the handleClick
function itself, without calling it (no parentheses ()
). React will automatically call your event handler function when the button is clicked.
Updating the Screen with State
To make components dynamic and remember information that changes over time (like a button click counter), you need to use state. State allows components to “remember” values and re-render the UI when those values change.
First, import the useState
Hook from React:
import { useState } from 'react';
Then, inside your component, declare a state variable using useState
:
function MyButton() {
const [count, setCount] = useState(0);
// ...
}
useState
returns an array with two elements: the current state value (count
) and a function to update it (setCount
). The initial state value (here, 0
) is passed as an argument to useState()
.
To update the state and trigger a re-render, call the setCount
function with the new state value. Here’s how to increment a counter when a button is clicked:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
When setCount(count + 1)
is called, React re-renders the MyButton
component. This time, count
will have the updated value (1
, then 2
, and so on), and the UI will reflect the change.
If you render the same component multiple times, each instance maintains its own independent state.
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
Each button in this example keeps track of its own count
state independently.
Using Hooks
Functions that begin with use
(like useState
) are called Hooks. useState
is a built-in Hook provided by React. React offers other built-in Hooks (see the React API reference), and you can also create your own custom Hooks.
Hooks have a crucial rule: they must be called at the top level of your components or other Hooks. You cannot call Hooks inside conditions, loops, or nested functions within components. If you need to use state or other Hook features conditionally, extract that logic into a separate component.
Sharing Data Between Components
In the previous counter example, each MyButton
component managed its own count
. But in many scenarios, you need components to share data and update in sync.
Initially, each MyButton
’s count
state is 0
The first MyButton
updates its count
to 1
To make multiple MyButton
components share the same counter and update together, you need to lift the state up. This means moving the state from the individual MyButton
components to their nearest common ancestor component, which in this case is MyApp
.
Initially, MyApp
’s count
state is 0
and is passed down to both children
On click, MyApp
updates its count
state to 1
and passes it down to both children
Here’s how to implement state lifting:
First, move the useState
declaration and the handleClick
function from MyButton
to MyApp
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... state logic removed from here ...
}
Next, pass the count
state and the handleClick
event handler down to each MyButton
component as props. Props are how parent components pass data to their children. Use JSX curly braces to pass props, similar to how you set attributes on HTML tags:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
Now, modify MyButton
to receive these props. Component props are accessed as arguments to the component function using destructuring:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
When a MyButton
is clicked, the onClick
prop (which is the handleClick
function from MyApp
) is executed. This updates the count
state in MyApp
, causing MyApp
and all its child MyButton
components to re-render with the new count
value. This is the essence of “lifting state up” – sharing state to coordinate updates across components.
import { useState } from 'react';
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
Next Steps in Learning ReactJS
Congratulations! You’ve now grasped the fundamental concepts of React development.
To solidify your understanding and build your first React application, proceed to the React Tutorial. This tutorial will guide you through creating a mini-application and putting your new React skills into practice.