1. Introduction to React
React is a JavaScript library used for building user interfaces, particularly single-page applications where you need a fast and interactive user experience. React allows developers to create large web applications that can change data, without reloading the page. It’s maintained by Facebook and a community of individual developers and companies.
React’s core concept is the component. Components are reusable UI elements that can manage their own state. React applications are built by combining these components to form complex user interfaces.
2. JSX (JavaScript XML)
JSX is a syntax extension for JavaScript that looks similar to HTML. It allows you to write HTML-like code within your JavaScript files. JSX makes it easier to write and add HTML in React, and it’s then transpiled to JavaScript by tools like Babel before being executed by the browser.
2.1 Example of JSX
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(element, document.getElementById('root'));
In this example, JSX allows you to embed HTML tags within JavaScript. The JSX syntax above will be transformed into a call to React.createElement()
before being rendered to the DOM.
2.2 Why JSX?
JSX helps developers to write UI elements and their logic in a more readable format, making the code easier to understand and maintain. It also allows for the use of JavaScript expressions inside HTML-like code, which can be powerful for dynamic content generation.
3. Components
Components are the building blocks of a React application. A component can be thought of as a self-contained module that renders some output based on the input it receives (known as props) and its internal state. Components can be classified as either functional components or class components.
3.1 Functional Components
Functional components are JavaScript functions that accept props as an argument and return React elements. They are simpler and easier to write compared to class components, especially when you don’t need to manage complex state or lifecycle methods.
3.1.1 Example: Functional Component
function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}
ReactDOM.render(<Greeting name="World" />, document.getElementById('root'));
3.2 Class Components
Class components are ES6 classes that extend from React.Component
. They can have their own state and lifecycle methods, making them more suitable for complex components that need to handle local state or side effects.
3.2.1 Example: Class Component
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
ReactDOM.render(<Welcome name="World" />, document.getElementById('root'));
4. State and Props
In React, state and props are two types of data that control how components behave and render.
4.1 Props (Properties)
Props are short for properties and are read-only data passed from a parent component to a child component. Props allow components to be dynamic and reusable, as they can be customized with different values.
4.1.1 Example: Passing Props
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
ReactDOM.render(<Welcome name="Alice" />, document.getElementById('root'));
In this example, the name
prop is passed to the Welcome
component, allowing it to display different names.
4.2 State
State is a built-in React object that allows components to create and manage their own local state. State can be updated with the setState
method in class components or by using the useState
hook in functional components. When the state changes, React re-renders the component to reflect the new state.
4.2.1 Example: Managing State in a Class Component
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
ReactDOM.render(<Counter />, document.getElementById('root'));
4.2.2 Example: Managing State in a Functional Component
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('root'));
In these examples, a simple counter component is created using both class and functional components. The counter increments its value every time the button is clicked.
5. Lifecycle Methods
Lifecycle methods are special methods in React class components that get called at different stages of a component's life in the DOM. They allow you to perform actions such as fetching data, cleaning up resources, or responding to user input at specific points in a component's lifecycle.
5.1 Common Lifecycle Methods
- componentDidMount: Called once the component has been inserted into the DOM. This is often where you initiate network requests or set up subscriptions.
- componentDidUpdate: Called after the component updates (i.e., after a state or prop change).
- componentWillUnmount: Called right before the component is removed from the DOM. This is where you should clean up subscriptions or timers.
5.1.1 Example: Using Lifecycle Methods
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
componentDidMount() {
this.interval = setInterval(() => this.setState({ seconds: this.state.seconds + 1 }), 1000);
}
componentDidUpdate() {
console.log(`Timer updated: ${this.state.seconds} seconds`);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <p>Timer: {this.state.seconds} seconds</p>;
}
}
ReactDOM.render(<Timer />, document.getElementById('root'));
This example demonstrates a timer component that updates every second. The componentDidMount
method starts the timer, componentDidUpdate
logs the updates, and componentWillUnmount
clears the timer when the component is removed.
6. Handling Events
Handling events in React is very similar to handling events in plain HTML, but with a few differences. In React, events are named using camelCase, rather than lowercase, and you pass a function as the event handler rather than a string.
6.1 Example: Handling a Click Event
function ActionButton() {
function handleClick() {
alert('Button was clicked!');
}
return (
<button onClick={handleClick}>Click Me</button>
);
}
ReactDOM.render(<ActionButton />, document.getElementById('root'));
In this example, the handleClick
function is called when the button is clicked. React’s event handling system ensures that the correct event is passed to your event handler function.
6.2 Event Binding in Class Components
In class components, you often need to bind event handlers to the class instance. This can be done in the constructor, or by using an arrow function, which automatically binds the method to the class instance.
6.2.1 Example: Event Binding in a Class Component
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isOn: true };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({ isOn: !state.isOn }));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(<Toggle />, document.getElementById('root'));
In this example, the handleClick
method is bound to the class instance in the constructor, allowing it to correctly update the component’s state when the button is clicked.
7. Forms in React
Forms in React work similarly to how they do in plain HTML, but with more control over the form’s data. In React, the form’s data is usually handled by the component’s state.
7.1 Controlled Components
A controlled component is an input element whose value is controlled by the React component’s state. This gives you full control over the form data.
7.1.1 Example: Controlled Component
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<NameForm />, document.getElementById('root'));
In this example, the value of the input field is controlled by the component’s state. The form data is managed by the React component, making it easier to validate and submit the data.
8. React Hooks
React Hooks are functions that let you use state and other React features in functional components. Introduced in React 16.8, hooks allow you to use features like state management and lifecycle methods without writing class components.
8.1 useState Hook
The useState
hook allows you to add state to functional components. You can declare a state variable and a function to update it, similar to this.state
and this.setState
in class components.
8.1.1 Example: useState Hook
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('root'));
In this example, the useState
hook is used to manage the count state in a functional component.
8.2 useEffect Hook
The useEffect
hook allows you to perform side effects in your functional components, such as fetching data, setting up a subscription, or manually changing the DOM. It serves the same purpose as lifecycle methods in class components.
8.2.1 Example: useEffect Hook
function Timer() {
const [seconds, setSeconds] = React.useState(0);
React.useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds => seconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <p>Timer: {seconds} seconds</p>;
}
ReactDOM.render(<Timer />, document.getElementById('root'));
In this example, the useEffect
hook sets up an interval that updates the seconds state every second. The cleanup function clears the interval when the component unmounts.