Essential JavaScript Fundamentals for React Development
JavaScript Prerequisites for React
React has become one of the most popular libraries for building user interfaces, and for good reason. As a view-only library focused on the UI layer, it integrates seamlessly with any stack. The relatively straightforward API minimizes the learning curve, while JSX enables developers to write HTML-like syntax directly within JavaScript. React's unidirectional data flow makes applications predictable and easier to debug, and its massive, growing community ensures abundant resources and third-party libraries.
However, working effectively with React requires solid JavaScript fundamentals, particularly ES6 and beyond.
Variable Declarations and Operators
Modern Variable Declarations
Before ES6, var was the only way to declare variables in JavaScript. ES6 introduced two additional keywords that offer better scoping behavior:
const: Declares a read-only constant that cannot be reassigned or redeclaredlet: Declares a block-scoped varible that can be reassignedvar: Function-scoped or globally-scoped (largely superseded byletandconst)
Best practices for variable declarations:
- Avoid
varentirely - Use
constas the default choice for variables that won't be reassigned - Use
letonly when reassignment is necessary - Preference order:
const>let>var
JavaScript Operators
JavaScript operators fall into several categories:
| Category | Examples |
|---|---|
| Arithmetic | +, -, *, /, %, **, ++, -- |
| Assignment | =, +=, -=, *=, /=, %= |
| Logical | &&, ` |
| Comparison | ==, !=, ===, !==, >, >=, <, <= |
| Bitwise | &, ` |
| Ternary | ? : |
// Arithmetic operations
console.log(10 + 5); // 15
console.log(10 - 3); // 7
console.log(4 * 2); // 8
console.log(15 / 4); // 3.75
console.log(17 % 5); // 2
console.log(2 ** 4); // 16
// Logical operations
console.log(true && false); // false
console.log(true || false); // true
console.log(!true); // false
// Comparison operations
console.log(5 === '5'); // false (strict equality)
console.log(5 == '5'); // true (loose equality)
Expressions and Keywords
JavaScript expressions evaluate to values. Key expression-related keywords include:
this: References the current object contextsuper: Invokes parent object methods or constructorfunction: Defines a functionfunction*: Defines a generator functionasync function: Defines an asynchronous function
Destructuring in JavaScript
Destructuring allows unpacking values from arrays or properties from objects into distinct variables, making code cleaner and more readable.
Object Destructuring
const employee = {
empId: 'E42',
fullName: 'Sarah Connor',
rating: '4.8'
};
// Traditional property access
const empId = employee.empId;
const fullName = employee.fullName;
const rating = employee.rating;
// Using destructuring
const { empId, fullName, rating } = employee;
// Destructuring with renaming
const { empId: employeeId, fullName: employeeName } = employee;
Destructuring in React Components
// Without destructuring
function Header(props) {
return <h1>{props.title}</h1>;
}
// With destructuring
function Header({ title }) {
return <h1>{title}</h1>;
}
Array Destructuring with Rest Operator
const { items, ...remaining } = this.props;
Spread Operator
The spread operator (...) expands iterable objects, useful for array concatenation, object merging, and passing arguments.
// Array concatenation
const arr1 = [10, 20, 30];
const arr2 = [40, 50, 60];
const combined = [...arr1, ...arr2];
console.log(combined); // [10, 20, 30, 40, 50, 60]
// Merging objects with additional properties
const person = { firstName: 'Alex' };
const worker = { empId: 'W99', department: 'Engineering' };
const profile = { ...person, ...worker, level: 'Senior' };
console.log(profile);
// { firstName: 'Alex', empId: 'W99', department: 'Engineering', level: 'Senior' }
Functions in JavaScript
Functions are first-class citizens in JavaScript, meaning they can be assigned to variables, passed as arguments, returned from other functions, and have properties and methods.
Function Types
Named Functions: Can be called recursively within their body and are hoisted to the top of their scope.
function calculateTotal(price, tax) {
return price + tax;
}
Anonymous Functions: Assigned to variables, cannot call themselves recursively.
const multiply = function(a, b) {
return a * b;
};
Generator Functions: Use yield to return a Generator object with a next() method.
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
Arrow Functions: Introduced in ES6, providing concise syntax and lexical this binding.
const add = (a, b) => a + b;
const square = x => x * x;
const greet = () => 'Hello!';
Key arrow function rules:
- Single-line bodies can omit
returnand curly braces - Single parameters don't require parentheses
- Zero parameters require empty parentheses
Arrow Functions in React
// Without arrow functions
const attendees = [
{ id: 1, checked: true },
{ id: 2, checked: true },
{ id: 3, checked: false }
];
const checkedIn = attendees.filter(function(person) {
return person.checked;
});
// With arrow functions
const checkedIn = attendees.filter(person => person.checked);
Higher-Order Functions
Higher-order functions take functions as arguments or return functions. They're powerful for creating reusable logic.
import React from 'react';
function createFilter(query) {
return function(user) {
return query === user.name;
};
}
// Arrow function version
const createFilter = query => user => query === user.name;
export default class UserList extends React.Component {
constructor(props) {
super(props);
this.state = { searchTerm: '' };
this.handleSearch = this.handleSearch.bind(this);
}
handleSearch(event) {
this.setState({ searchTerm: event.target.value });
}
render() {
const team = [
{ name: 'Emma' },
{ name: 'James' }
];
return (
<div>
<ul>
{team
.filter(createFilter(this.state.searchTerm))
.map(member => <li key={member.name}>{member.name}</li>)}
</ul>
<input type="text" onChange={this.handleSearch} />
</div>
);
}
}
Extracting Logic for Testability
Separating business logic from React components enables unit testing of state transformations.
import React from 'react';
export const increment = state => ({ count: state.count + 1 });
export const decrement = state => ({ count: state.count - 1 });
export default class Counter extends React.Component {
state = { count: 0 };
handleIncrement = () => this.setState(increment);
handleDecrement = () => this.setState(decrement);
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleIncrement}>+</button>
<button onClick={this.handleDecrement}>-</button>
</div>
);
}
}
Array Methods: Map, Reduce, Filter
- Map: Transforms array elements, returns new array
- Reduce: Aggregates array into single value
- Filter: Selects elements meeting condition, returns new array
Classes and Objects
ES6 introduced class syntax to JavaScript, providing a cleaner way to implement object-oriented patterns. Classes are syntactic sugar over JavaScript's prototype-based inheritance.
Class Declaration
class Engineer {
constructor(firstName, lastName, expertise) {
this.firstName = firstName;
this.lastName = lastName;
this.expertise = expertise;
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
getInfo() {
return `${this.getFullName()} specializes in ${this.expertise}`;
}
}
const dev = new Engineer('Lisa', 'Wang', 'Frontend');
console.log(dev.getInfo());
Object Literals
const laptop = {
manufacturer: 'Dell',
memory: '16GB',
speed: '3.2GHz',
showSpecs() {
console.log(`${this.manufacturer}: ${this.memory} RAM`);
}
};
The this Keyword and Method Binding
JavaScript's this binding can be explicit using call(), apply(), or bind().
- call(): Invokes function with specified
thisand individual arguments - apply(): Invokes function with specified
thisand array of arguments - bind(): Creates new function with permanently bound
this
// call() example
const mathObj = { multiplier: 5 };
const calculate = function(x, y) {
return this.multiplier * (x + y);
};
console.log(calculate.call(mathObj, 3, 7)); // 50
// apply() example
const numbers = [2, 4, 6];
const sum = function(a, b, c) {
return a + b + c;
};
console.log(sum.apply(null, numbers)); // 12
// bind() example
const server = {
port: 3000,
getPort() {
return this.port;
}
};
const getServerPort = server.getPort.bind(server);
console.log(getServerPort()); // 3000
Class Inheritance
Classes can extend other classes to inherit properties and methods.
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
getDescription() {
return `${this.make} ${this.model}`;
}
}
class Car extends Vehicle {
constructor(make, model, doors) {
super(make, model);
this.doors = doors;
}
getDescription() {
return `${super.getDescription()} - ${this.doors} doors`;
}
}
Inheritance versus Composition:
While React historically used class components with inheritance, composition is generally preferred:
- Inheritance creates IS-A relationships (subclass IS-A superclass)
- Composition creates HAS-A relationships (class HAS-A instance of another class)
Composition advantages:
- More flexible than rigid inheritance hierarchies
- Reduces coupling between components
- Easier to refactor and adapt to changing requirements
JavaScript Modules
Modules organize code into reusable, independently-maintainable units.
Export and Import
By default, module members are private. Use export to make them public and import to access them.
// Named exports
export const API_URL = 'https://api.example.com';
export function fetchData() {}
// Default export
export default class DataService {}
// Importing named exports
import { API_URL, fetchData } from './services';
// Importing default export
import DataService from './services';
JavaScript Ecosystem for React
Several libraries and frameworks complement React development:
- React Router: Client-side routing for single-page applications
- Redux/MobX: State management solutions for complex application state
- React Bootstrap/Material-UI: UI component libraries
- React Native: Cross-platform mobile development
- Next.js: Server-side rendering and static site generation
React Component Fundamentals
Component-Based Architecture
React applications are built from components—self-contained, reusable pieces of UI.
Props
Components accept inputs through props, passed from parent to child. Props are read-only.
function Welcome({ name, role }) {
return (
<div>
<h1>Hello, {name}</h1>
<p>Role: {role}</p>
</div>
);
}
State
Components manage internal data through state, private to each component and updated via setState().
Class Components versus Function Components
Class Components:
- Use ES6 class syntax extending
React.Component - Have access to lifecycle methods
- Manage state via
this.stateandthis.setState()
Function Components:
- Simpler functions accepting props and returning JSX
- Originally stateless (without hooks)
- Act as pure functions with same inputs producing same outputs
Modern React combines both approaches, with hooks enabling function components to manage state and side effects while class components remain available for legacy codebases.