ReactJS is a popular JavaScript library for building user interfaces.
Developed and maintained by Facebook.
Used to create interactive, reusable UI components.
Key Features
React Ecosystem Example
Components can have state.
State is mutable data that influences rendering.
Components can receive props (properties).
Props are read-only and help pass data from parent to child.
my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
└── setupTests.jssrc/index.js is the JavaScript entry point.public/index.html is the page template.package.json contains following command to manage the applicationnpm start – Starts the development server.npm run build – Bundles the app into static files for production.npm test – Starts the test runner.npm run eject – Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back!public/index.html defines root element for our applicationsrc/index.js, ReactDOM get holds of root element and renders React Componentsrc/App.js defines the React Component with name App
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}Remove everything in between ( ) of return and Just write <h2>Hello World!!!</h2>
constructor, componentDidMount, and componentWillUnmount.onClick and onChange trigger handlers.if statements or ternary operators.map method to iterate and create components.key to each list item for efficient updates.import React, { Component } from 'react';
class NameForm extends Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
handleSubmit = (event) => {
alert('Name submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<button type="submit">Submit</button>
</form>
);
}
}{}.<div>).className and style.React.createElement() calls.{}.if statements can be used within {}.key for efficient rendering.onClick, onChange, and more.Nested components are components within other components.
They enable complex UI structures and modular development.
Advantages of Nested Components
Let’s explore a music search app.
This app allows users to search for music on iTunes.
Components in the App
App (Parent Component)
SearchBar (Child Component)
SearchResults (Child Component)
App ComponentSearchBar ComponentApp) using props and callbacks.import React, { Component } from 'react';
class SearchBar extends Component {
constructor() {
super();
this.state = { query: '' };
}
handleInputChange = (event) => {
this.setState({ query: event.target.value });
}
handleSearch = () => {
// Perform search and update parent's state
this.props.onSearch(this.state.query);
}
render() {
return (
<div>
<input
type="text"
value={this.state.query}
onChange={this.handleInputChange}
/>
<button onClick={this.handleSearch}>Search</button>
</div>
);
}
}SearchResults ComponentApp) via props.SearchBar communicates search queries to App.App fetches data and passes it to SearchResults.SearchBar sends the query to App.App fetches music data.App updates the state with the results.SearchResults displays the search results.
function Track() {
return ( // OK Return single DIV as root element
<div>
<h4>Track Name: Jack Johnson</h4>
<p>artistName: This Bike Is a Pipe Bomb</p>
</div>
)
}
function Track() {
return ( // NOT OK Multiple root elements
<div>
<h4>Track Name: Jack Johnson</h4>
<p>artistName: This Bike Is a Pipe Bomb</p>
</div>
<div>
<img src="https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/f3/ee/b3/f3eeb3ff-ca32-273a-15aa-709bdfa64367/mzi.izwiyqez.jpg/30x30bb.jpg" />
</div>
)
}
const track = {
title: "Let It Be",
artist: "The Beatles",
album: "This Bike Is a Pipe Bomb",
coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/f3/ee/b3/f3eeb3ff-ca32-273a-15aa-709bdfa64367/mzi.izwiyqez.jpg/100x100bb.jpg"
}
function Track() {
return (
<div>
<h4>Track Name: {track.title}</h4>
<div>
<div style={{ "float": "left", "paddingRight": "12px" }}>
<img src={track.coverUrl} alt={track.title} width={100} height={100} />
</div>
<div>
Artist: {track.artist} <br />
Album Name: {track.album}<br />
Last Fetched On: {Date()}<br />
</div>
</div>
</div>
)
}name prop is passed from the parent component.count property in the component’s state is displayed in the render method.class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
incrementCount() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
Count: {this.state.count}
<button onClick={() => this.incrementCount()}>Increment</button>
</div>
);
}
}setState is used to update the state, which triggers a re-render of the component.Styling in React refers to how you apply CSS styles to your components.
Several approaches for styling in React, including traditional CSS, CSS modules, and CSS-in-JS.
Why Styling Matters
Using traditional CSS files to style React components.
Styles can be applied using class names.
Pros
Cons
CSS Modules are a solution for local CSS scoping in React.
Each component gets its own isolated scope for styles.
How It Works
.module.css file.Pros
A popular CSS-in-JS library for styling in React.
Styles are defined as JavaScript template literals.
Provides dynamic styling and theming capabilities.
How It Works
Pros
Maintain consistency in your project’s styling approach.
Use CSS Modules or Styled-Components for local scoping.
Keep styles close to the components they affect.
Consider using a CSS preprocessor like SASS or LESS for advanced styling.
CSS Preprocessors
// Button.module.css
.button {
background-color: #0077b6;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
// Button.js
import React from 'react';
import styles from './Button.module.css';
function Button() {
return <button className={styles.button}>Click me</button>;
}redux and react-redux packages in your project.createStore.Provider component to wrap your app in Redux.// store.js
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);type property that describes the action.payload property.dispatch from react-redux.connect function to connect a component to the Redux store.redux-thunk for async actions and redux-logger for debugging.combineReducers to combine them into one root reducer.redux-thunk or other middleware for actions with async operations.const fetchTodos = () => {
return (dispatch) => {
dispatch({ type: 'FETCH_TODOS_REQUEST' });
// Perform async operation
fetch('/api/todos')
.then((response) => response.json())
.then((data) => {
dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: data });
})
.catch((error) => {
dispatch({ type: 'FETCH_TODOS_FAILURE', payload: error });
});
};
};Redux Toolkit is an official package for efficient state management in Redux.
It simplifies common Redux patterns and provides utilities to streamline development.
Why Redux Toolkit?
@reduxjs/toolkit package in your project.createSlice for each piece of state.configureStore to create the Redux store.useSelector to access specific parts of the state.configureStore, createSlice, useDispatch, and useSelector.react-redux for integrating Redux.@reduxjs/toolkit for Redux Toolkit.Project Structure
my-itunes-search-app/
src/
components/
features/
search/
results/
app/
store.js
index.js
searchSlice.jsimport { createSlice } from '@reduxjs/toolkit';
const searchSlice = createSlice({
name: 'search',
initialState: {
results: [],
loading: false,
error: null,
},
reducers: {
setSearchResults: (state, action) => {
state.results = action.payload;
state.loading = false;
state.error = null;
},
setSearchLoading: (state) => {
state.loading = true;
},
setSearchError: (state, action) => {
state.error = action.payload;
state.loading = false;
},
},
});
export const { setSearchResults, setSearchLoading, setSearchError } = searchSlice.actions;
export default searchSlice.reducer;configureStore.search slice to the store’s configuration.store.jsSearch component that dispatches search actions.useDispatch hook to dispatch actions.Search.jsimport React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { searchiTunes } from './searchSlice';
function Search() {
const [query, setQuery] = useState('');
const dispatch = useDispatch();
const handleSearch = () => {
dispatch(searchiTunes(query));
}
return (
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button onClick={handleSearch}>Search</button>
</div>
);
}createAsyncThunk for async actions.searchSlice.jsfulfilled, pending, and rejected reducers.searchSlice.jsconst searchSlice = createSlice({
name: 'search',
initialState: {
results: [],
loading: false,
error: null,
},
reducers: { /* ... */ },
extraReducers: (builder) => {
builder
.addCase(searchiTunes.fulfilled, (state, action) => {
state.results = action.payload;
state.loading = false;
state.error = null;
})
.addCase(searchiTunes.pending, (state) => {
state.loading = true;
})
.addCase(searchiTunes.rejected, (state, action) => {
state.error = action.error.message;
state.loading = false;
});
},
});Results component to display search results.useSelector hook to access the state.Results.jsSearch and Results components in your app.App.jsBrowserRouter, Route, Link, and Switch to facilitate routing.BrowserRouter component.Route component, specifying a path and the corresponding component to render.Link component.match.params.Switch component to ensure that only the first matching route is rendered.Redirect component to achieve this behavior.Route component with a render function to implement custom logic.react-transition-group.<Route path="/page" component={Page} />
.page-enter {
opacity: 0;
transform: scale(0.9);
}
.page-enter-active {
opacity: 1;
transform: scale(1);
transition: opacity 300ms, transform 300ms;
}
.page-exit {
opacity: 1;
transform: scale(1);
}
.page-exit-active {
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}useEffect hook in functional components.BrowserRouter, Route, and Link components.Unit Testing is a software testing technique where individual components or functions of a program are tested in isolation to ensure they work correctly.
Purpose
Jest is a popular JavaScript testing framework.
Developed by Facebook, it’s commonly used for testing JavaScript and TypeScript applications.
Jest is built on top of Jasmine and provides a rich set of features for writing unit tests.
Features
expect.Install Jest:
Create a test file:
Run the tests:
Test Suite: A collection of test cases for a specific module or component.
Create a test suite using describe:
Test Case: An individual test scenario within a test suite.
Create a test case using test:
expect is used for making assertions in Jest.toBe, toEqual, toBeTruthy, and more.Run all tests in the project:
Run specific test files or test suites:
Keep test files alongside the code to be tested (e.g., myFunction.js and myFunction.test.js).
Organize tests into folders and subfolders to match your project’s structure.
Common Matchers:
toBe(): Strict equality (===).toEqual(): Deep equality.not.toBeNull(): Ensure a value is not null.Chaining Matchers:
Negating Matchers:
toBe(value): Strict equality.toEqual(value): Deep equality.not: Inverts the matcher.toContain(item): Checks if an array or string contains an item.toMatch(regexp): Matches a string against a regular expression.Component Testing is the practice of testing individual React components in isolation to ensure they work as intended.
Importance of Component Testing
react-testing-library.toBeInTheDocument(): Checks if an element is in the document.toHaveTextContent(text): Checks for specific text content.toHaveAttribute(attrName): Checks for attributes.import { render, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('Counter increments when the button is clicked', () => {
const { getByText } = render(<Counter />);
const button = getByText('Increment');
fireEvent.click(button);
expect(getByText('Count: 1')).toBeInTheDocument();
});What is Mocking?
Why Mocking Is Important
Controlling Asynchronous Timers
Use jest.advanceTimersByTime(ms) to control timers:
axios:jest.mock:Asynchronous Testing
Using async/await
async/await simplifies testing asynchronous code.await is used to pause the test until the promise resolves or rejects..resolves and .rejects matchers to test promise resolutions and rejections.await with .resolves and .rejects for testing.jest.useFakeTimers() to control timers.setTimeout with a Promise to simulate delays in tests.