Introduction to React
React is a JavaScript library designed for building user interfaces. Originally developed as an internal project at Facebook, it was later open-sourced in 2013.
Key Characteristics:
- Declarative - Describe how the UI should appear, similar to writing HTML, while React handles the rendering
- Component-Based - Components are the core building blocks of React, representing parts of a page that can be combined and reused
- Learn Once, Write Anywhere - Use React for web applications, mobile development, and VR applications
Getting Started with React
Installation and Setup
1. Install React by executing: npm i react react-dom
reactprovides core functionality for creating elements and componentsreact-domoffers DOM-specific capabilities
2. Include the necessary JavaScript files:
<script src="../node_modules/react/umd/react.development.js"></script>
<script src="../node_modules/react-dom/umd/react-dom.development.js"></script>
3. Create and render React elements:
<body>
<div id="root"></div>
</body>
<script>
const header = React.createElement('h1', null, 'Getting Started with React')
ReactDOM.createRoot(document.getElementById('root')).render(header)
</script>
React.createElement API:
- Return value: React element
- First parameter: Element type to create
- Second parameter: Element properties
- Subsequent parameters: Child elements
const complexElement = React.createElement('h2', null, 'Welcome!', React.createElement('a', { href: 'https://example.com/' }, 'Example Link'))
ReactDOM.createRoot API:
Renders React elements into a specified DOM container.
React Development Environment
Using Create React App
Benefits of using the official scaffolding:
- Essential for modern web development
- Integrates tools like Webpack, Babel, and ESLint
- Zero configuration required
- Focus on business logic rather than tool setup
Project Initialization
1. Create a new project: npx create-react-app my-project
npx (introduced in npm v5.2.0) improves the experience of using package CLI tools without requiring global installation.
2. Start the development server: npm start
Alternative initialization methods:
npm init react-app my-projectyarn create react-app my-project(if using Yarn)
Yarn is Facebook's package manager, serving as an npm alternative with speed and reliability advantages.
React in the Scaffolding Environment
1. Import necessary packages:
import React from 'react'
import ReactDOM from 'react-dom/client'
2. Create and render elements:
const message = React.createElement('p', null, 'Hello from React!')
ReactDOM.createRoot(document.getElementById('root')).render(message)
JSX Syntax
JSX (JavaScript XML) provides a more intuitive way to write React components. It allows HTML-like syntax within JavaScript code, improving readability and development efficiency.
Basic JSX Usage
const greeting = <h2>Hello JSX!</h2>
ReactDOM.createRoot(document.getElementById('app')).render(greeting)
Why JSX Works in Create React App
- JSX is an ECMAScript syntax extension
- Babel compiles JSX to compatible JavaScript
- Create React App includes this configuration by default
- Compilation package:
@babel/preset-react
JSX Syntax Guidelines
- Use camelCase for property names
- Special attribute mappings:
class→className,for→htmlFor,tabindex→tabIndex - Self-closing tags can use
/> - Wrap JSX in parentheses to avoid automatic semicolon insertion issues
const card = (
<div className='card' />
)
ReactDOM.createRoot(document.getElementById('card')).render(card)
JavaScript Expressions in JSX
Embed expressions using {expression} syntax:
- Any valid JavaScript expression works
- JSX itself is a valid expression
- Objects are exceptions (typically used only in style attributes)
- Statements (if/for) are not allowed
const getMessage = () => 'Hello from function!'
const expressions = (
<div>
<p>{2 + 3}</p>
<p>{true ? 'Yes' : 'No'}</p>
<p>{getMessage()}</p>
</div>
)
ReactDOM.createRoot(document.getElementById('expressions')).render(expressions)
Conditional Rendering
Render different JSX based on conditions:
const isLoading = false
const renderContent = () => {
if (isLoading) {
return <div>Loading content...</div>
}
return <div>Content loaded</div>
}
const ternaryExample = isLoading ? <div>Loading...</div> : <div>Ready</div>
const logicalExample = isLoading && <div>Loading...</div>
List Rendering
Use array map() for rendering collections:
const items = [
{ id: 'a', label: 'First' },
{ id: 'b', label: 'Second' },
{ id: 'c', label: 'Third' }
]
const list = (
<ul>
{items.map(item => <li key={item.id}>{item.label}</li>)}
</ul>
)
ReactDOM.createRoot(document.getElementById('list')).render(list)
Important: Always include unique keys for list items. Avoid using array indices as keys when possible.
Styling in JSX
1. Inline styles (object notation):
const styledBox = (
<div style={{ backgroundColor: 'blue', padding: '20px' }}>
Styled content
</div>
)
2. CSS classes (recommended):
/* styles.css */
.container {
background: #f0f0f0;
padding: 15px;
border-radius: 5px;
}
// Component
import './styles.css'
const styledComponent = <div className='container'>Content</div>
React Components
Components are first-class citizens in React. They represent reusable parts of the user interface that can be composed together to build complete applications.
Function Components
Created using JavaScript functions or arrow functions:
- Name must start with uppercase letter
- Must return JSX or null
function WelcomeComponent() {
return <div>Welcome!</div>
}
const ArrowComponent = () => <div>Arrow function component</div>
const EmptyComponent = () => null
// Usage
ReactDOM.createRoot(document.getElementById('app')).render(<WelcomeComponent />)
Class Components
Created using ES6 classes:
- Name must start with uppercase letter
- Must extend React.Component
- Must implement render() method
class ClassComponent extends React.Component {
render() {
return <div>Class-based component</div>
}
}
// Usage
ReactDOM.createRoot(document.getElementById('app')).render(<ClassComponent />)
Component Organization
Extract components to separate files for better organization:
MyComponent.js:
import React from 'react'
class MyComponent extends React.Component {
render() {
return <div>Isolated component</div>
}
}
export default MyComponent
App.js:
import MyComponent from './MyComponent'
ReactDOM.createRoot(document.getElementById('app')).render(<MyComponent />)
Event Handling
React events use camelCase syntax:
// Function component
function ButtonComponent() {
const handleClick = (event) => {
event.preventDefault()
console.log('Button clicked')
}
return <button onClick={handleClick}>Click me</button>
}
// Class component
class ClassButton extends React.Component {
handleClick(event) {
event.preventDefault()
console.log('Button clicked')
}
render() {
return <button onClick={this.handleClick}>Click me</button>
}
}
React provides synthetic events that normalize behavior across browsers.
Stateful vs Stateless Components
Function components are typically stateless (presentational), while class components manage state (interactive).
State Management
State is private component data:
- Access via
this.state - Update using
this.setState() - Never modify state directly
class Counter extends React.Component {
state = {
value: 0
}
increment = () => {
this.setState({ value: this.state.value + 1 })
}
decrement() {
// 'this' will be undefined here without binding
this.setState({ value: this.state.value - 1 })
}
render() {
return (
<div>
<p>Count: {this.state.value}</p>
<button onClick={this.increment}>+</button>
<button onClick={() => this.decrement()}>-</button>
</div>
)
}
}
Binding Event Handlers
Three approaches to maintain correct 'this' context:
- Arrow function in render
- Bind in constructor
- Class property with arrow function (recommended)
class BindingExample extends React.Component {
constructor() {
super()
this.state = { count: 0 }
this.handleIncrement = this.handleIncrement.bind(this)
}
handleIncrement() {
this.setState({ count: this.state.count + 1 })
}
handleDecrement = () => {
this.setState({ count: this.state.count - 1 })
}
render() {
return (
<div>
<p>Value: {this.state.count}</p>
<button onClick={() => this.handleIncrement()}>Method 1</button>
<button onClick={this.handleIncrement}>Method 2</button>
<button onClick={this.handleDecrement}>Method 3</button>
</div>
)
}
}
Form Handling
Controlled Components
Form elements whose values are controlled by React state:
class FormExample extends React.Component {
state = {
username: '',
message: '',
city: 'ny',
agree: false
}
handleChange = (event) => {
const { name, value, type, checked } = event.target
this.setState({
[name]: type === 'checkbox' ? checked : value
})
}
render() {
return (
<div>
<input
name="username"
type="text"
value={this.state.username}
onChange={this.handleChange}
placeholder="Enter name"
/>
<br />
<textarea
name="message"
value={this.state.message}
onChange={this.handleChange}
placeholder="Enter message"
/>
<br />
<select
name="city"
value={this.state.city}
onChange={this.handleChange}
>
<option value="ny">New York</option>
<option value="la">Los Angeles</option>
<option value="ch">Chicago</option>
</select>
<br />
<input
name="agree"
type="checkbox"
checked={this.state.agree}
onChange={this.handleChange}
/> I agree
</div>
)
}
}
Uncontrolled Components
Use refs to access form values directly:
class UncontrolledForm extends React.Component {
inputRef = React.createRef()
handleSubmit = () => {
console.log('Input value:', this.inputRef.current.value)
}
render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.handleSubmit}>Submit</button>
</div>
)
}
}
Comment System Example
class CommentSystem extends React.Component {
state = {
comments: [
{ id: 1, author: 'Alice', text: 'First comment!' },
{ id: 2, author: 'Bob', text: 'Great post!' },
{ id: 3, author: 'Charlie', text: 'Thanks for sharing' }
],
newAuthor: '',
newText: ''
}
handleInputChange = (event) => {
const { name, value } = event.target
this.setState({ [name]: value })
}
addComment = () => {
const { newAuthor, newText } = this.state
if (!newAuthor.trim() || !newText.trim()) {
alert('Please fill in both fields')
return
}
const newComment = {
id: Date.now(),
author: newAuthor,
text: newText
}
this.setState({
comments: [newComment, ...this.state.comments],
newAuthor: '',
newText: ''
})
}
renderComments() {
return this.state.comments.map(comment => (
<li key={comment.id}>
<h4>{comment.author}</h4>
<p>{comment.text}</p>
</li>
))
}
render() {
return (
<div className="comment-system">
<h3>Leave a Comment</h3>
<input
name="newAuthor"
value={this.state.newAuthor}
onChange={this.handleInputChange}
placeholder="Your name"
/>
<br />
<textarea
name="newText"
value={this.state.newText}
onChange={this.handleInputChange}
placeholder="Your comment"
/>
<br />
<button onClick={this.addComment}>Post Comment</button>
<h3>Comments</h3>
{this.state.comments.length === 0 ? (
<p>No comments yet. Be the first!</p>
) : (
<ul>{this.renderComments()}</ul>
)}
</div>
)
}
}