MERN - ReactJS Fundamentals
Core Concepts
Components: The building blocks of a React application. They are functional and are used to encapsulate parts of the UI.
JSX: A syntax extension that allows writing HTML-like code in JavaScript, which React transforms into JavaScript objects.
Props: Short for properties, props are read-only inputs to components used to pass data and event handlers down the component tree.
State: A special object in React components that determines how components render and behave.
Hooks: Special functions that let you use state and other React features in functional components.
graph LR
subgraph reactApp["fa:fa-desktop React Application"]
jsx["fa:fa-code JSX"]
props["fa:fa-list Props"]
state["fa:fa-database State"]
hooks["fa:fa-plug Hooks"]
end
style jsx fill:#ccf,stroke:#f66,stroke-width:2px
style props fill:#ff9,stroke:#333,stroke-width:2px
style state fill:#add8e6,stroke:#333,stroke-width:2px
style hooks fill:#9cf,stroke:#333,stroke-width:2px
Functional Components
Functional components are simple JavaScript functions that return JSX.
1
2
3
4
5
6
7
import React from 'react';
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
export default Greeting;
JSX
JSX allows you to write HTML-like syntax within JavaScript. It is then transformed into JavaScript objects.
1
const element = <h1>Hello, world!</h1>;
Props
Props are used to pass data and event handlers to components. They are read-only.
1
2
3
4
5
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
State
State is a special object that controls how a component renders and behaves. State can be updated using useState
in functional components.
Using State in Functional Components with Hooks
1
2
3
4
5
6
7
8
9
10
11
12
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Hooks
Hooks are special functions that let you use state and other React features in functional components.
useEffect Hook
The useEffect
hook lets you perform side effects in functional components, such as data fetching or subscribing to events.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds => seconds + 1);
}, 1000);
// Cleanup interval on unmount
return () => clearInterval(interval);
}, []);
return (
<div>
<h1>Timer: {seconds}s</h1>
</div>
);
}
export default Timer;
useContext Hook
The useContext
hook lets you access the value of a context in functional components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemeToggler() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
);
}
export default ThemeToggler;
Life cycle
Custom Hook
Custom hooks are functions that let you reuse logic across multiple components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { useState, useEffect } from 'react';
function useUser() {
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Fetch user data from an API or local storage
// ...
setIsLoading(false);
}, []);
const login = (credentials) => {
// Implement login logic
// ...
};
const logout = () => {
// Implement logout logic
// ...
};
return { user, isLoading, login, logout };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { useState, useEffect } from 'react';
function useUser() {
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Fetch user data from an API or local storage
// ...
setIsLoading(false);
}, []);
const login = (credentials) => {
// Implement login logic
// ...
};
const logout = () => {
// Implement logout logic
// ...
};
return { user, isLoading, login, logout };
}
Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
Handling Events
Handling events in React is similar to handling events in HTML. You can use event handlers like onClick
, onChange
, etc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Toggle() {
const [isOn, setIsOn] = useState(false);
function handleClick() {
setIsOn(!isOn);
}
return (
<button onClick={handleClick}>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
export default Toggle;
Conditional Rendering
You can conditionally render components in React using JavaScript expressions.
1
2
3
4
5
6
7
8
9
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
return (
<div>
{isLoggedIn ? <UserGreeting /> : <GuestGreeting />}
</div>
);
}
Lists and Keys
You can render lists of items in React using JavaScript map
function.
1
2
3
4
5
6
7
8
9
10
11
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) => (
<li key={number.toString()}>{number}</li>
))}
</ul>
);
}
Controlled Components
Controlled components are form elements whose value is controlled by React state.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function NameForm() {
const [name, setName] = useState('');
function handleChange(event) {
setName(event.target.value);
}
function handleSubmit(event) {
alert('Name submitted: ' + name);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={name} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
Uncontrolled Components
Uncontrolled components are form elements whose value is handled by the DOM.
Use refs when you need to access the DOM directly to handle form input. For example, to get the value of an input field or to focus an input field.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function NameForm() {
const inputRef = useRef(null);
function handleSubmit(event) {
alert('Name submitted: ' + inputRef.current.value);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={inputRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
Forms
You can handle form input in React using controlled components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function NameForm() {
const [name, setName] = useState('');
function handleChange(event) {
setName(event.target.value);
}
function handleSubmit(event) {
alert('Name submitted: ' + name);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={name} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
Lifting State Up
Lifting state up is a technique in React where you move the state from child components to their parent component.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child count={count} setCount={setCount} />
</div>
);
}
function Child({ count, setCount }) {
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Composition
Composition is a technique in React where components can be composed together to create more complex components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">Welcome</h1>
<p className="Dialog-message">Thank you for visiting our spacecraft!</p>
</FancyBorder>
);
}
React Router
React Router is a library that allows you to handle routing in a React application.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
}
Got it. Here are the additional topics that were not mentioned previously:
Programmatic Navigation
Programmatic navigation allows you to navigate to different routes programmatically.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { useHistory } from 'react-router-dom';
function MyComponent() {
let history = useHistory();
function handleClick() {
history.push("/new-path");
}
return (
<button onClick={handleClick}>
Go to new path
</button>
);
}
Higher-Order Components (HOCs):
Higher-order components are functions that take a component and return a new component with additional props.
Higher-Order Components (HOCs)
Higher-Order Components (HOCs) are an advanced technique in React for reusing component logic. An HOC is a function that takes a component and returns a new component.
Why Use HOCs?
HOCs allow you to:
- Share common functionality between components.
- Enhance components with additional behavior.
- Abstract repetitive logic.
Creating an HOC
A simple example of an HOC is one that adds a loading spinner while data is being fetched.
1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
function withLoadingSpinner(WrappedComponent) {
return function WithLoadingSpinner(props) {
if (props.isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} />;
};
}
export default withLoadingSpinner;
In this example, withLoadingSpinner
is a higher-order component that wraps another component and displays a loading spinner based on the isLoading
prop.
Using HOCs
To use the HOC, simply wrap the component you want to enhance with the HOC function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React, { useState, useEffect } from 'react';
import withLoadingSpinner from './withLoadingSpinner';
function DataComponent(props) {
return (
<div>
<h1>Data:</h1>
<pre>{JSON.stringify(props.data, null, 2)}</pre>
</div>
);
}
const DataComponentWithLoading = withLoadingSpinner(DataComponent);
function App() {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setData({ name: 'React' });
setIsLoading(false);
}, 2000);
}, []);
return <DataComponentWithLoading isLoading={isLoading} data={data} />;
}
export default App;
Testing
Testing is an important part of building React applications. You can write tests for React components using tools like Jest and React Testing Library.
Jest is a JavaScript testing framework that is commonly used for testing React applications.
To write tests for React components, create test files with the .test.js
or .spec.js
extension.
1
2
3
4
5
6
7
8
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});