React Tutorial, with practical examples, real-world applications, and industry best practices. ☔
MIT License
React is a JavaScript library for creating user interfaces. It enables developers to build reusable UI components and efficiently update the DOM by using a virtual DOM for optimal performance.
If you want to create a new app or website entirely with React, I suggest choosing one of the React-powered frameworks that are popular in the community.
You can use React without a framework, but we have found that most apps and sites eventually need to address common issues like code splitting, routing, data fetching, and HTML generation. These challenges are not unique to React but are common to all UI libraries.
By starting with a framework, you can quickly get up and running with React and avoid the need to develop your own framework later.
Next.js’ Pages Router is a full-stack React framework. It’s versatile and lets you create React apps of any size—from a mostly static blog to a complex dynamic application. To create a new Next.js project, run in your terminal:
npx create-next-app@latest
Next.js is maintained by Vercel. You can deploy a Next.js app to any Node.js or serverless hosting, or to your own server. Next.js also supports a static export which doesn’t require a server.
O App Router do Next.js is a redesign of the Next.js APIs aiming to fulfill the React team’s full-stack architecture vision. It lets you fetch data in asynchronous components that run on the server or even during the build.
Next.js is maintained by Vercel. You can deploy a Next.js app to any Node.js or serverless hosting, or to your own server. Next.js also supports static export which doesn’t require a server.
Overview Vite (French word for "quick", pronounced /vit/, like "veet") is a build tool that aims to provide a faster and leaner development experience for modern web projects. It consists of two major parts:
A dev server that provides rich feature enhancements over native ES modules, for example extremely fast Hot Module Replacement (HMR).
A build command that bundles your code with Rollup, pre-configured to output highly optimized static assets for production.
Vite is opinionated and comes with sensible defaults out of the box. Read about what's possible in the Features Guide. Support for frameworks or integration with other tools is possible through Plugins. The Config Section explains how to adapt Vite to your project if needed.
Before you begin, make sure you have Node.js installed on your system. If you don’t have it yet, you can download it from the official Node.js website, it’s really simple.
npx create-vite your-project-name --template react
Replace your-project-name with the name you want for your project. Vite supports many frameworks, but in this case, we specify the react template with the --template react option.
cd your-project-name
Don’t forget to replace your-project-name with the actual name you chose for your project (unless of course, you want to keep this name for your project).
npm
npm run dev
After running these commands, you should see a message in your terminal indicating that your React website is running on a specific port, it’s usually a ‘random’ port number like http://localhost:5173. Now, open your browser and visit the provided URL to see your React website in action.
Use React Developer Tools to inspect React components, edit props and state, and identify performance problems.
Browser extension The easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular browsers:
For other browsers (for example, Safari), install the react-devtools npm package:
# Yarn
yarn global add react-devtools
# Npm
npm install -g react-devtools
Next open the developer tools from the terminal:
react-devtools
Then connect your website by adding the following tag to the beginning of your website’s :
<html>
<head>
<script src="http://localhost:8097"></script>
JSX is a syntax extension for JavaScript that looks similar to XML or HTML. It allows developers to write HTML elements and components in a more concise and readable manner within JavaScript files.
import React from 'react';
function App() {
return (
<div>
<h1>Hello, React!</h1>
</div>
);
}
export default App;
Functional components are simple functions that accept props as an argument and return JSX elements. With React Hooks, functional components can also have state and side effects.
import React from 'react';
const FunctionalComponent = () => {
return <p>This is a functional component.</p>;
}
export default FunctionalComponent;
Class components are ES6 classes that extend the React Component. They can maintain and manage local state and have access to lifecycle methods, making them more feature-rich than functional components.
import React, { Component } from 'react';
class ClassComponent extends Component {
render() {
return <p>This is a class component.</p>;
}
}
export default ClassComponent;
Props are a way of passing data from a parent component to a child component in React. They are immutable and provide a way of making components dynamic and reusable.
import React from 'react';
const PropsExample = (props) => {
return <p>{props.message}</p>;
}
export default PropsExample;
State React represents the changing state of a component. This allows components to manage and update their own data, resulting in dynamic and interactive user interfaces.
import React, { Component } from 'react';
class StateExample extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Increment
</button>
</div>
);
}
}
export default StateExample;
Lifecycle methods são métodos especiais em componentes de classe que são invocados em diferentes fases do ciclo de vida de um componente. componentDidMount é um método de ciclo de vida comummente utilizado, executado depois de um componente ser renderizado no DOM.
import React, { Component } from 'react';
class LifecycleExample extends Component {
componentDidMount() {
console.log('Component is mounted!');
}
render() {
return <p>Lifecycle Example</p>;
}
}
export default LifecycleExample;
React uses camelCase to handle events. Functions can be defined to handle events such as clicks, changes, etc., providing interactivity to the components.
import React from 'react';
const EventHandlingExample = () => {
const handleClick = () => {
alert('Button clicked!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
export default EventHandlingExample;
React Hooks are functions that allow functional components to manage state and side effects. They were introduced in React 16.8 and provide a more concise way of working with state and lifecycle methods in functional components.
import React, { useState } from 'react';
const UseStateExample = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
export default UseStateExample;
Controlled components in React have inputs and their state controlled by React. They receive their current value and the onChange handler as props, making them controlled by React and not by the DOM.
import React, { useState } from 'react';
const ControlledComponent = () => {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
}
return (
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder="Type here"
/>
);
}
export default ControlledComponent;
Error boundaries are React components that detect JavaScript errors anywhere in the child component tree and log those errors, present a fallback UI or take other action.
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <p>Something went wrong.</p>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Higher Order Components (HOCs) are functions that take a component and return a new component with additional functionality. They are a way of reusing the component's logic.
import React from 'react';
const WithLogger = (WrappedComponent) => {
return class extends React.Component {
componentDidMount() {
console.log('Component is mounted!');
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
export default WithLogger;
// Usage
import React from 'react';
import WithLogger from './WithLogger';
const MyComponent = () => {
return <p>My Component</p>;
}
const EnhancedComponent = WithLogger(MyComponent);
React provides the map
function to render lists of items dynamically. Each item in the array is mapped to a React element, making it easier to render dynamic content.
import React from 'react';
const RenderingList = () => {
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
export default RenderingList;
The Context API in React offers a way of transmitting data through the component tree without having to pass props manually at each level. It's useful for sharing values such as themes or authentication status.
import React from 'react';
const ThemeContext = React.createContext('light');
export default ThemeContext;
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
const ThemedComponent = () => {
const theme = useContext(ThemeContext);
return <p style={{ color: theme === 'light' ? 'black' : 'white' }}>Themed Component</p>;
}
export default ThemedComponent;
Keys in React help identify which items have been changed, added or removed. They should be unique within the list and help React with efficient updates.
import React from 'react';
const KeysExample = () => {
const data = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
export default KeysExample;
Handling forms in React involves managing form data using state and handling form submission via event handlers. Controlled components are used to synchronize form elements with React's state.
import React, { useState } from 'react';
const FormExample = () => {
const [formData, setFormData] = useState({ username: '', password: '' });
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
}
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted:', formData);
}
return (
<form onSubmit={handleSubmit}>
<label>
Username:
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
/>
</label>
<label>
Password:
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</label>
<button type="submit">Submit</button>
</form>
);
}
export default FormExample;
Inline Styles: React allows you to style components using inline styles, where styles are defined as objects and applied directly to elements.
import React from 'react';
const InlineStyleExample = () => {
const styles = {
color: 'blue',
fontSize: '18px',
};
return <p style={styles}>Styled with inline styles</p>;
}
export default InlineStyleExample;
Render Props is a technique for sharing code between React components using a prop whose value is a function. This allows for the dynamic composition of components.
import React, { useState } from 'react';
const MouseTracker = ({ render }) => {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (event) => {
setPosition({ x: event.clientX, y: event.clientY });
}
return (
<div style={{ height: '100vh' }} onMouseMove={handleMouseMove}>
{render(position)}
</div>
);
}
export default MouseTracker;
// Usage
import React from 'react';
import MouseTracker from './MouseTracker';
const App = () => {
return (
<MouseTracker
render={(position) => (
<p>
Mouse position: {position.x}, {position.y}
</p>
)}
/>
);
}
export default App;
CSS Modules help define the scope of styles for a specific component, avoiding global style conflicts. Each component can have its own CSS module with locally scoped styles.
.myComponent {
color: green;
}
import React from 'react';
import styles from './CSSModulesExample.module.css';
const CSSModulesExample = () => {
return <p className={styles.myComponent}>Styled with CSS Modules</p>;
}
export default CSSModulesExample;
Features:
import React, { useState } from 'react';
const TodoApp = () => {
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState('');
const addTask = () => {
setTasks([...tasks, { text: newTask, completed: false }]);
setNewTask('');
};
const toggleTask = (index) => {
const updatedTasks = [...tasks];
updatedTasks[index].completed = !updatedTasks[index].completed;
setTasks(updatedTasks);
};
const removeTask = (index) => {
const updatedTasks = [...tasks];
updatedTasks.splice(index, 1);
setTasks(updatedTasks);
};
return (
<div>
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
/>
<button onClick={addTask}>Add Task</button>
<ul>
{tasks.map((task, index) => (
<li key={index}>
<input
type="checkbox"
checked={task.completed}
onChange={() => toggleTask(index)}
/>
<span style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.text}
</span>
<button onClick={() => removeTask(index)}>Remove</button>
</li>
))}
</ul>
</div>
);
};
export default TodoApp;
This weather application example illustrates the practical application of React concepts, including state management, useEffect for side effects, event handling, API interaction and conditional rendering. Users can learn how to create a functional weather application and understand the integration of React hooks into real-world scenarios.
Fetaures:
Functional Component and State Hooks:
useState
hooks for weather
and city
.Using useEffect to obtain data:
The useEffect
hooks are used to perform side effects, such as fetching weather data from the OpenWeatherMap API.
The fetchWeatherData
function is asynchronous and fetches weather data based on the selected city using the fetch
API.
Conditional Rendering:
The weather data is conditionally rendered only if it exists (weather && ...
).
Event Handling:
setCity
function is called on its onChange
event.API Interaction:
Dynamically Updating Content:
Styling:
Temperature Conversion:
// src/RealWorldExamples/WeatherApp.js
import React, { useState, useEffect } from 'react';
const WeatherApp = () => {
const [weather, setWeather] = useState(null);
const [city, setCity] = useState('New York');
const apiKey = 'YOUR_OPENWEATHERMAP_API_KEY';
useEffect(() => {
// Fetch weather data from OpenWeatherMap API
const fetchWeatherData = async () => {
try {
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`
);
if (!response.ok) {
throw new Error('Failed to fetch weather data');
}
const data = await response.json();
setWeather(data);
} catch (error) {
console.error(error.message);
}
};
fetchWeatherData();
}, [city, apiKey]);
return (
<div>
<h1>Weather App</h1>
<label>
Enter City:
<input
type="text"
value={city}
onChange={(e) => setCity(e.target.value)}
/>
</label>
{weather && (
<div>
<h2>{weather.name}, {weather.sys.country}</h2>
<p>Temperature: {Math.round(weather.main.temp - 273.15)}°C</p>
<p>Weather: {weather.weather[0].description}</p>
</div>
)}
</div>
);
};
export default WeatherApp;
Best practices:
/src
/components
/Button
Button.js
Button.test.js
Button.css
/features
/Todo
TodoList.js
TodoItem.js
TodoForm.js
/styles
global.css
/tests
/unit
Button.test.js
/integration
TodoIntegration.test.js
Best practices:
// Using React.memo
const MemoizedComponent = React.memo(({ data }) => {
// Component logic
});
// Using Code Splitting and Lazy Loading
const MyComponent = React.lazy(() => import('./MyComponent'));
// In your component
const App = () => (
<React.Suspense fallback={<LoadingSpinner />}>
<MyComponent />
</React.Suspense>
);
Best practices:
Example:
// Jest Unit Test
test('renders correctly', () => {
const { getByText } = render(<Button label="Click me" />);
expect(getByText('Click me')).toBeInTheDocument();
});
// Jest Integration Test
test('increments count on button click', () => {
const { getByText } = render(<Counter />);
fireEvent.click(getByText('Increment'));
expect(getByText('Count: 1')).toBeInTheDocument();
});
// React Testing Library
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('clicking button increments count', () => {
render(<MyComponent />);
userEvent.click(screen.getByRole('button'));
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
Best practices:
Use React Router for client-side routing in a single-page application.
Define routes to different views or sections of your application.
Implement navigation components, such as <Link>
, to allow easy navigation between routes.
Example:
// React Router
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const App = () => (
<Router>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Router>
);
Best practice:
// Using Local Component State
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
// Using Context API
const ThemeContext = React.createContext('light');
const ThemedComponent = () => {
const theme = useContext(ThemeContext);
return <p style={{ color: theme === 'light' ? 'black' : 'white' }}>Themed Component</p>;
};
// Using Redux
// (Assuming you have a Redux store configured)
import { useSelector, useDispatch } from 'react-redux';
const CounterRedux = () => {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
</div>
);
};
Best practices:
Example:
Best practices:
Example:
// Error Boundary
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <p>Something went wrong. Please try again.</p>;
}
return this.props.children;
}
}
Best practices:
Example:
// Semantic HTML Elements
<article>
<h2>Article Title</h2>
<p>Article content...</p>
</article>
// ARIA Roles and Attributes
<button aria-label="Close" onClick={handleClose}>
✕
</button>
// Keyboard Navigation
<input type="text" onKeyDown={handleKeyDown} />
Best practices:
Example:
// Using React.memo
const MemoizedComponent = React.memo(({ data }) => {
// Component logic
});
// Using Code Splitting and Lazy Loading
const MyComponent = React.lazy(() => import('./MyComponent'));
// In your component
const App = () => (
<React.Suspense fallback={<LoadingSpinner />}>
<MyComponent />
</React.Suspense>
);
// Using PureComponent
class PureCounter extends React.PureComponent {
render() {
return <p>Count: {this.props.count}</p>;
}
Regularly update dependencies to benefit from new features, bug fixes and security patches.
Follow semantic versioning for libraries and packages used in the project.
Be cautious with major updates and test thoroughly before updating.
Example:
# Regularly update dependencies
npm update
# Follow semantic versioning
# Example: Major.Minor.Patch
# ^1.2.3 means any version that is compatible with 1.2.3
Configure Webpack for production builds with optimizations:
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
// Other webpack configurations...
};
Thank you for your interest in contributing to this Amazing React Tutorial! Your contributions help make this resource even more valuable to students of all levels. Whether you're fixing a bug, improving an existing feature or adding something entirely new, your efforts make a difference.
**Fork the Repository: Click on the "Fork" button in the top right corner of this repository to create your copy.
**Clone the Repository: Clone the repository to your local machine using git clone https://github.com/DaveSimoes/React-Tutorial-2024.git
**Create a Branch: Create a new branch for your contribution with a descriptive name: git checkout -b your-feature
.
**Make changes: Make your changes in the appropriate files. Feel free to improve existing examples, add new ones, correct typos or improve the documentation.
**Commit changes: Submit your changes with a clear and concise message: git commit -m "Your message here"
.
**Push Changes: Send your changes to the forked repository: git push origin your-feature
.
Create a Pull Request: Open a pull request in the original repository. Forneça um título claro, descreva suas alterações e envie o pull request.
Follow consistent coding styles. Make sure your code is well documented, especially if you are adding new examples or features.
Thank you for considering contributing to this React Tutorial. Your dedication to making this resource better is greatly appreciated. Let's learn and grow together!
If you found this React Tutorial useful, consider giving it a star! ⭐ Your support is incredibly motivating and helps others discover this resource. Thank you for being part of our community and hap! 🚀
React Official Library