Fundamentals
Before we start
This page will give you an introduction to 80% of React. If you understand the concepts on this page, you will be able to understand the rest of the React documentation.
You will learn about:
- Creating React components
- Adding markup and styles
- Displaying data
- Rendering conditions and lists
- Handling events
- Updating the screen
- Side effects
- Hooks
Creating React components
React apps are made out of components. A component is a piece of the UI (user interface), a building block that has its logic and design (appearance). It is a JavaScript function that returns an HTML element, which could be as small as a button, or as large as an entire page. You can think of components as a custom HTML element. For example, you can create a Header component, and use it in your app like this:
function MyHeader() {
return <h1>My First React App</h1>;
}
Now that you've declared the Header component, you can use it in another component like this:
function App() {
function MyHeader() {
return <h1>My First React App</h1>;
}
return (
<div>
<MyHeader />
<p>This is an example of a React component.</p>
</div>
);
}
Above, is a live example of the code, you can change the code and see the result in real-time
Let's try to change the text inside the MyHeader component and see the result.
Notice that <MyHeader /> starts with a capital letter. That’s how you know it’s a React component. React component names must always start with a capital letter, while HTML tags are always lowercase.
If the component is in a different file (i.e. src/components/MyHeader.js) like this:
function MyHeader() {
return <h1>My First React App</h1>;
}
export default MyHeader;
If you want to use a component in another file make sure to export it using the export default or just export keyword. Otherwise, you won't be able to import it into another file.
You can import it into another file like this:
import MyHeader from "./components/MyHeader";
function App() {
return (
<div>
<MyHeader />
<p>This is an example of React component.</p>
</div>
);
}
If you don't understand how import and export work in JavaScript, must can read about it here.
Adding markup and styles
Adding markup
The markup syntax you’ve seen above is called JSX (JavaScript XML). It is optional, but most React projects use JSX for its convenience. JSX is a syntax extension to JavaScript. It is similar to a template language, but it has full power of JavaScript.
JSX is stricter than HTML like:
-
You have to close tags like
<br />. -
Your component also can’t return multiple JSX tags. You have to wrap them into a shared parent, like a
<div>...</div>or an empty<></>wrapper:function AboutPage() {return (<><h1>About</h1><p>Hello there.<br />How do you do?</p></>);} -
etc.
Commenting in JSX code is a bit different from HTML and JS. You can use {/* */} to comment out a line of code like this:
function App() {
return (
<div>
{/* This is a comment */}
<p>This is an example of React component.</p>
</div>
);
}
Adding styles
In React, you specify a CSS class with className. It works the same way as the HTML class attribute:
First, write your CSS in a separate file:
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
}
Then import the CSS file in your component:
import "./App.css";
function App() {
return <img className="avatar" />;
}
React does not prescribe how you add CSS files. In the simplest case, you’ll add a <link> tag to your HTML. If you use a build tool or a framework, consult its documentation to learn how to add a CSS file to your project.
You can also add styles inline. This is not recommended for most cases, but it can be useful for quick prototyping:
The style attribute accepts a JavaScript object with camelCased properties. You can use the style attribute to add inline styles to your elements. The value of the style attribute must be an object where the keys are camelCased versions of the CSS property names, and the values are the CSS property values:
Let's see an example:
<>
<h1 style={{ color: "red" }}>Hello, world!</h1>
<p style={{ color: "blue", fontSize: "20px" }}>
This is an example of <b>inline styles</b>.
</p>
<div
style={{
backgroundColor: "orange",
borderRadius: "10px",
padding: "10px",
margin: "10px",
color: "white",
}}
>
<h1>Styles of div</h1>
<p style={{ color: "blue" }}>But here I override the color</p>
</div>
</>
I would recommend you to learn what CSS properties are available and how to use them. You can learn about CSS properties from MDN Web Docs.
Displaying data
JSX lets you put markup into JavaScript, and it also lets you put JavaScript into markup. You can embed JavaScript expressions inside JSX by wrapping them in curly braces {}. This is useful for displaying variables, calling functions, and more. Check this example:
function App() {
const name = "Rizwan";
return <h1>Hello, {name}</h1>;
}
You can also embed JavaScript expressions inside JSX. For example, this will display the sum of two numbers:
<h1>{2 + 2}</h1>
Let's see another example:
function Profile() {
const user = {
name: "Muhammad Ali Jinnah",
imageUrl:
"https://moderndiplomacy.eu/wp-content/uploads/2021/08/jinnah.jpg",
imageSize: "50%",
};
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={"Photo of " + user.name}
style={{
width: user.imageSize,
}}
/>
</>
);
}
In the above example, style={{}} is not a special syntax, but a regular {} object inside the style={ } JSX curly braces. You can use the style attribute when your styles depend on JavaScript variables.
Let's create and call a function:
function App() {
function formatName(user) {
return user.firstName + " " + user.lastName;
}
const user = {
firstName: "Rizwan",
lastName: "Ashiq",
};
return <h1>Hello, {formatName(user)}!</h1>;
}
Even you can assign HTML elements to variables and use them in JSX:
function App() {
const heading = <h1>Hello, world!</h1>;
return <>{heading}</>;
}
Rendering conditions and lists
Conditional rendering
React also allows you to render different UIs based on some conditions. You can use if...else statements, the ternary operator, or the && operator to conditionally render elements.
Let's learn from some examples:
function App() {
const isLoggedIn = true;
if (isLoggedIn) {
return <h1>Admin Panel</h1>;
} else {
return <h1>Login Form</h1>;
}
}
or
function App() {
const isLoggedIn = true;
let content;
if (isLoggedIn) {
content = <h1>Admin Panel</h1>;
} else {
content = <h1>Login Form</h1>;
}
return <>{content}</>;
// or return content;
}
You can also use the ternary operator:
function App() {
const isLoggedIn = true;
return <>{isLoggedIn ? <h1>Admin Panel</h1> : <h1>Login Form</h1>}</>;
}
Sometimes you might want to only render a component if a condition is true, and otherwise render nothing, then you can use the && operator:
function App() {
const isLoggedIn = true;
return <>{isLoggedIn && <h1>Admin Panel</h1>}</>;
}
Rendering lists
You can use the map() function to render a list of items.
The map() function creates a new array with the results of calling a provided function on every element in the calling array.
I would recommend you to read map() function, and how to use it in JS.
In React, map() can be handy, we can use it to transform an array of items into an array of elements.
For example, let's say you have a list of products:
const products = [
{ title: "Cabbage", id: 1 },
{ title: "Garlic", id: 2 },
{ title: "Apple", id: 3 },
];
Inside your component, use the map() function to transform an array of products into an array of <li> items:
const listItems = products.map((product) => (
<li key={product.id}>{product.title}</li>
));
return <ul>{listItems}</ul>;
Notice how <li> has a key attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React uses your keys to know what happens if you later insert, delete, or reorder the items.
function ShoppingList() {
const products = [
{ title: "Cabbage", isFruit: false, id: 1 },
{ title: "Garlic", isFruit: false, id: 2 },
{ title: "Apple", isFruit: true, id: 3 },
];
const listItems = products.map((product) => (
<li
key={product.id}
style={{
color: product.isFruit ? "magenta": "darkgreen",
}}
>
{product.title}
</li>
));
return <ul>{listItems}</ul>;
}
In above code, I used <li>, and <ul> tags. You can learn more about HTML tags from Here
And instead of storing the list items in a variable, you can directly return the result of the map() function:
function ShoppingList() {
const products = [
{ title: "Cabbage", isFruit: false, id: 1 },
{ title: "Garlic", isFruit: false, id: 2 },
{ title: "Apple", isFruit: true, id: 3 },
];
return (
<ul>
{products.map((product) => (
<li
key={product.id}
style={{
color: product.isFruit ? "magenta" : "darkgreen",
}}
>
{product.title}
</li>
))}
</ul>
);
}
Handling events
Handling events with React elements is very similar to handling events on DOM elements. There are some syntax differences:
- React events are named using camelCase, rather than lowercase.
- With JSX you pass a function as the event handler, rather than a string.
- You can't return
falseto prevent default behavior in React. You must callpreventDefaultexplicitly. - etc
For example, the HTML:
<button onclick="activateLasers()">Activate Lasers</button>
is slightly different from React:
<button onClick={activateLasers}>Activate Lasers</button>
for handling events in React, you pass a function as the event handler, rather than a string.
Here, activateLasers is a function that is defined somewhere in your code. You can pass it as a prop to the onClick event handler. The onClick event handler will call the activateLasers function when the button is clicked.
Check this example:
function App() {
const handleClick = () => {
alert("Button clicked");
};
return <button onClick={handleClick}>Click me</button>;
}
Updating the screen
Often, you’ll want your component to “remember” some information and display it.
For example, maybe you want to count the number of times a button is clicked. Let me show you a code snippet:
function MyButton() {
let count = 0;
const handleClick = () => {
count++;
alert("Button clicked " + count + " times");
};
return (
<>
<h1>Clicked {count} times</h1>
<button onClick={handleClick}>Click me</button>
</>
);
}
When you click the button, the count variable will be incremented, but the screen won’t update. However, the alert will show the correct value. This is because React doesn’t automatically re-render your component when a variable's value changes.
So, how can you make React re-render your component when a variable's value changes?
The answer is the useState hook. Let’s see how it works.
To do this, add a state to your component. First, import useState from React:
import { useState } from "react";
Now you can declare a state variable inside your component:
function MyButton() {
const [count, setCount] = useState(0);
// ...
}
You’ll get two things from useState:
- the current state (
count) - the function that lets you update it (
setCount).
You can give them any names, but the convention is to write [something, setSomething].
The first time the button is displayed, count will be 0 because you passed 0 to useState(). When you want to change state, call setCount() and pass the new value to it. Clicking this button will increment the counter:
function MyButton() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
alert("Button clicked " + count + " times");
};
return (
<>
<h1>Clicked {count} times</h1>
<button onClick={handleClick}>Click me</button>
</>
);
}
React will call your component function again. This time, count will be 1. Then it will be 2. And so on.
If you render the same component multiple times, each will get its state. Click each button separately:
function MyApp() {
function MyButton() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
alert("Button clicked " + count + " times");
};
return (
<>
<h1>Clicked {count} times</h1>
<button onClick={handleClick}>Click me</button>
</>
);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<br />
<MyButton />
</div>
);
}
State variables might look like regular JavaScript variables that you can read and write to. However, the state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render.
Side effects
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.
Looking at this code:
function MyComponent() {
const [data, setData] = useState([]);
const fetchData = async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts",
);
const data = await response.json();
setData(data.slice(0, 5)); // get only the first 5 items
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
return (
<div>
{data.map((item) => (
<div
key={item.id}
style={{
border: "1px solid goldenrod",
backgroundColor: "rgba(0, 128, 0, 0.5)",
padding: "10px",
marginBottom: "10px",
}}
>
<h3>{item.title}</h3>
<p>{item.body}</p>
<p>UserID: {item.userId}</p>
</div>
))}
</div>
);
}
What do you think will happen when you run this code?
The callingAPI function will be called every time the component renders. This is not what we want. We only want to call the API once, when the component first renders. For this, we can use useEffect hook.
useEffect is a function that takes a function as an argument. This function will be called after the component renders. Let’s see how it works:
function MyComponent() {
const [data, setData] = useState([]);
const fetchData = async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts",
);
const data = await response.json();
setData(data.slice(0, 5)); // only first 5 items
} catch (error) {
console.error("Error fetching data:", error);
}
};
useEffect(() => fetchData(), []);
return (
<div>
{data.map((item) => (
<div
key={item.id}
style={{
border: "1px solid goldenrod",
backgroundColor: "rgba(0, 128, 0, 0.5)",
padding: "10px",
marginBottom: "10px",
}}
>
<h3>{item.title}</h3>
<p>{item.body}</p>
<p>UserID: {item.userId}</p>
</div>
))}
</div>
);
}
Hooks
In React, a Hook is a function that lets you "hook into" React state and lifecycle features from functional components. They were introduced in React 16.8 as a way to use state and other React features without having to write a class component.
There are several built-in Hooks in React, including:
useState- lets you add and update state in a function componentuseEffect- lets you perform lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmountuseContext- lets you use React context, which is a way to pass data through the component tree without having to pass props down manually at every leveluseReducer- lets you manage complex state logic in a function componentuseCallback- lets you memoize a function so that it only changes if one of its dependencies changesuseMemo- lets you memoize a value so that it only changes if one of its dependencies changesuseRef- lets you create a mutable ref object that persists for the full lifetime of the component- etc
Hooks allow developers to write more concise and expressive code while still providing access to the same powerful features of class components.
Hooks are more restrictive than other functions. You can only call Hooks at the top of your components (or other Hooks). If you want to use useState in a condition or a loop, extract a new component and put it there.
For example, this code will not work:
function MyComponent() {
const [count, setCount] = useState(0);
if (count > 0) {
const [name, setName] = useState("John");
}
return <div>...</div>;
}
I did not import useState in the example above, but you must import it before using it in your code.
import { useState } from "react";
You can only call Hooks at the top level of your component. You can’t call them inside loops, conditions, or nested functions. If you want to define a state variable conditionally, you can do it inside a component:
function MyComponent() {
const [count, setCount] = useState(0);
return (
<div>
{count > 0 && <Name />}
<div>...</div>
</div>
);
}
function Name() {
const [name, setName] = useState("John");
return <div>{name}</div>;
}
Don't worry if you don't understand the code above. We'll cover it in more detail in another lesson.
For now, just remember you can't define a state variable inside a condition or a loop.