Full Stack Camp
Ir al canal en Telegram
Fullstack Camp | Learn. Build. Launch. Join us for a hands-on journey through HTML, CSS, JavaScript, React, Node.js, Express & MongoDB — all in one place. Use this bot to search for lessons. @FullstackCamp_assistant_bot DM: @Tarikey6
Mostrar másEl país no está especificadoLa categoría no está especificada
236
Suscriptores
Sin datos24 horas
+37 días
+530 días
Archivo de publicaciones
🧩 Week 9 Day 5 Challenges
Challenge 1: Bookmark Manager with Redux Toolkit & Express
Build a bookmark storage app where users can save, tag, and organize their favorite links.
Requirements:
➜ Set up an Express server with GET /api/bookmarks, POST /api/bookmarks, and DELETE /api/bookmarks/:id endpoints. Use an in-memory array (or JSON file) for storage.
➜ Use Redux Toolkit to create a bookmarksSlice with createAsyncThunk for fetching, adding, and deleting bookmarks from your Express backend.
➜ Configure the Redux store with the bookmarks reducer and provide it to your app via <Provider>.
➜ Create a BookmarkList component that uses useSelector and useDispatch to display the bookmarks, show loading/error states, and handle form submission for adding new links.
Challenge 2: Habit Tracker Dashboard with Zustand & LocalStorage Sync
Track daily habits with persistence and a clean dashboard—no backend required for this one, just Zustand plus localStorage.
Requirements:
➜ Create a Zustand store called useHabitStore with state: habits (array), loading (boolean), error (string). Add actions: fetchHabits (reads from localStorage), addHabit, toggleHabit (mark done/undone), and deleteHabit.
➜ Use a custom hook useLocalStorage inside your Zustand actions to sync the habits array to localStorage automatically after every mutation. On initial load, fetchHabits should pull from localStorage.
➜ Use useMemo inside the HabitStats component to calculate the completion rate, current streak, and total active habits without recalculating on every habit toggle.
➜ Use useTransition to mark the habit filter (All / Active / Completed) as a low-priority update, ensuring the toggle buttons remain responsive even with 100 habits.
➜ Use createPortal to render a "Quick Add" modal that floats above the dashboard when the user presses the + button.
Challenge 3: Recipe Finder with RTK Query & Express
Build a recipe discovery app that searches a remote API (or your own Express mock) and caches results intelligently.
Requirements:
➜ Set up an Express server with GET /api/recipes?search=query that returns an array of recipe objects (use a mock dataset or the Spoonacular API).
➜ Use RTK Query's createApi with fetchBaseQuery to define a getRecipes query endpoint and a saveRecipe mutation endpoint for saving favorites.
➜ Use the auto-generated useGetRecipesQuery hook in your SearchPage component. Pass the search term as a query parameter. RTK Query will automatically cache results.
➜ Use useGetRecipesQuery's isFetching and isError flags to show loading spinners and error messages gracefully.
➜ Use useMemo to compute a list of unique recipe categories from the returned data to display as filter chips.
➜ Use useCallback to memoize the search handler that updates the search term state.
➜ Lazy-load the RecipeDetail page using React.lazy and <Suspense> so the user only loads the heavy description and image gallery when they click a recipe.
➜ Use NavLink with active styling to highlight the "Search" and "Favorites" navigation items.
When you are done,
💥 Share your solutions,
💥 invite a friend,
and as always —
💥 stay well, stay curious, and stay coding ✌️
Part 2 --- Zustand: The Minimalist Powerhouse
Zustand (German for "state") provides global state management without the complexity of Redux. Instead of using providers and separate action/reducer files, Zustand allows you to create a store with a single custom hook that defines state and mutation functions through a simple API. There are no dispatch functions or boilerplate reducers—just a plain JavaScript object with methods for updates. This simplicity leads to a shallower learning curve and faster prototyping. Zustand also optimizes component re-renders by preventing updates unless the relevant state changes, making it ideal for mid-sized applications and MVPs.
Installing Zustand
bash
npm install zustand
Creating a Store with Zustand
Stores are created using the create function. You provide a callback that receives set and get functions, and returns your state object along with methods to modify it. Notice how everything lives in one cohesive block—no separate actions or reducers.
jsx
// store/useUserStore.js
import { create } from "zustand";
const useUserStore = create((set, get) => ({
// State
name: "Guest",
isLoggedIn: false,
preferences: { theme: "dark" },
todos: [],
// Actions (methods that update state)
login: (name) => set({ name, isLoggedIn: true }),
logout: () => set({ name: "Guest", isLoggedIn: false }),
toggleTheme: () => set((state) => ({
preferences: {
...state.preferences,
theme: state.preferences.theme === "dark" ? "light" : "dark"
}
})),
addTodo: (text) => set((state) => ({
todos: [...state.todos, { id: Date.now(), text, done: false }]
})),
// Using get to access current state inside actions
getTodoCount: () => get().todos.length
}));
export default useUserStore;
Using Zustand in Components
To use the store inside a component, you invoke the custom hook and destructure exactly the pieces you need. Zustand's selector pattern ensures your component only re-renders when those specific fields change—similar to Redux's useSelector but built-in.
jsx
// components/Dashboard.jsx
import useUserStore from "../store/useUserStore";
function Dashboard() {
// Select only what you need—no unnecessary re-renders!
const { name, isLoggedIn, login, logout, toggleTheme, todos } = useUserStore();
// Or select a single field with a selector function
const todoCount = useUserStore((state) => state.todos.length);
return (
<div>
<p>User: {name}</p>
<p>Todo count: {todoCount}</p>
<button onClick={() => login("Megersa")}>Login</button>
<button onClick={logout}>Logout</button>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
} `🌟 Week 9 Day 5 --- Redux & Zustand
Good Evening campers 💙
Part 1 --- Redux Toolkit (RTK)
Redux has been the standard for large-scale React applications for nearly a decade, centralizing application state in a single object called the "store." Instead of mutating this object directly, you dispatch "actions" that describe changes, and pure "reducers" compute the next state based on these actions. This unidirectional data flow simplifies debugging with Redux DevTools. However, classic Redux involved extensive boilerplate, requiring action creators, constants, and complex update logic for each feature. Redux Toolkit (RTK) addresses this by providing sensible defaults, using Immer for simpler updates, and automatically generating actions from reducers, resulting in significantly less code while maintaining predictability.
Installing Redux Toolkit and React-Redux
npm install @reduxjs/toolkit react-redux
Creating a Slice (the modern reducer)
A slice bundles together a piece of state, its reducers, and the actions that trigger them. Think of it as a self-contained module for a specific domain—like user, products, or cart.
// store/userSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
name: "Guest",
isLoggedIn: false,
preferences: { theme: "dark" }
};
const userSlice = createSlice({
name: "user",
initialState,
reducers: {
login: (state, action) => {
// Thanks to Immer, we can "mutate" the state directly!
state.name = action.payload.name;
state.isLoggedIn = true;
},
logout: (state) => {
state.name = "Guest";
state.isLoggedIn = false;
},
toggleTheme: (state) => {
state.preferences.theme = state.preferences.theme === "dark" ? "light" : "dark";
}
}
});
// Export the generated action creators
export const { login, logout, toggleTheme } = userSlice.actions;
// Export the reducer to be included in the store
export default userSlice.reducer;
Configuring the Store
The store is the central registry of all your application's state. You combine all your slices into a single root reducer and pass it to configureStore, which automatically sets up the Redux DevTools and middleware like Redux Thunk for async logic.
// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./userSlice";
import cartReducer from "./cartSlice";
export const store = configureStore({
reducer: {
user: userReducer,
cart: cartReducer
}
});
Providing the Store to Your React App
Wrap your entire application with the <Provider> component from React-Redux. This gives every component in the tree access to the store using hooks.
jsx
// main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./store";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<Provider store={store}>
<App />
</Provider>
);
Using State and Dispatching Actions in Components
Inside any component, you read state with useSelector and send actions with useDispatch. The selector function subscribes to the Redux store and automatically re-renders your component only when the selected data changes—giving you fine-grained performance control without manual memoization.
jsx
// components/UserProfile.jsx
import { useSelector, useDispatch } from "react-redux";
import { login, logout, toggleTheme } from "../store/userSlice";
function UserProfile() {
const dispatch = useDispatch();
const { name, isLoggedIn, preferences } = useSelector((state) => state.user);
const handleLogin = () => {
dispatch(login({ name: "Megersa" }));
};
return (
<div>
<p>Welcome, {name}!</p>
<p>Theme: {preferences.theme}</p>
<button onClick={handleLogin}>Login</button>
<button onClick={() => dispatch(logout())}>Logout</button>
<button onClick={() => dispatch(toggleTheme())}>Toggle Theme</button>
</div>
);
}In 2026, making your website visible and navigable to AI agents is essential because modern users no longer just search the web; they deploy autonomous AI assistants to discover, compare, and summarize services for them. If your application cannot be easily parsed by AI crawlers, it effectively becomes invisible to the next generation of web traffic.
To achieve this discoverability safely, you must strictly separate your public content from your protected data. Ensure that public-facing pages use Server-Side Rendering (SSR) to deliver fully formed HTML, leverage standard
robots.txt files to guide permitted bots, and implement Schema.org JSON-LD structured data so AI agents can instantly comprehend your app's core purpose without guessing.
Security remains completely uncompromised during this process though because AI agents interact with your platform exactly like anonymous, logged-out visitors. While bots crawl your public semantic structures, your backend continues to shield private user data behind secure, server-side HttpOnly JWT cookies. Any attempt by an AI crawler to access private endpoints - such as user dashboards or checkout screens - will be instantly blocked with a 401 Unauthorized response since the bot lacks the necessary session cookies.
By explicitly structuring your public routes for machine readability while leaving your authentication walls intact, you can safely maximize your application's reach in the AI-driven ecosystem.🧩 Week 9 Day 4 Challenges
Challenge 1: Creature Pokedex & Team Builder
Build a Pokémon-style creature collector where users search, filter, and build a battle team.
Requirements:
➜ Use useEffect + fetch to pull creatures from an API (e.g., PokéAPI or similar). Use a custom useFetch hook.
➜ Use dynamic routing: /creature/:id to show detailed stats using useParams.
➜ Manage your "Battle Team" (max 6) using useReducer (actions: ADD, REMOVE, REORDER). Share this state globally via Context.
➜ Use useMemo to calculate average stats (HP, Attack) of your team efficiently.
➜ Use React.memo on the creature card list to prevent re-renders while typing in the search filter.
➜ Lazy-load the "Battle Simulator" page using React.lazy + Suspense.
➜ Render a stats comparison modal using createPortal (outside the root div).
➜ Use useNavigate for a "Go Back" button on detail pages.
---
Challenge 2: Recipe Box & Meal Planner
A cooking app where users browse recipes, filter by cuisine, and plan meals for the week.
Requirements:
➜ Use useState for controlled search/filter inputs, and useRef to focus the search bar on mount.
➜ Use dynamic routes: /recipe/:slug for detailed instructions using useParams.
➜ Manage the "Weekly Meal Plan" (Monday–Sunday) using useReducer (actions: ADD_MEAL, REMOVE_MEAL, CLEAR_DAY). Share via Context.
➜ Use useMemo to calculate total prep time and calorie count for the week's plan.
➜ Use useTransition to keep the cuisine-filter dropdown smooth when filtering a large recipe list.
➜ Create a custom useLocalStorage hook to persist the meal plan automatically.
➜ Lazy-load the "Grocery List" page (generates shopping items from the plan).
➜ Use forwardRef to allow the parent to clear the search input from outside.
---
Challenge 3: Productivity Dashboard (Goal & Habit Tracker)
Track daily habits and long-term goals with live analytics — far beyond a simple checklist.
Requirements:
➜ Use useReducer to manage habits (actions: LOG_HABIT, DELETE_HABIT, EDIT_GOAL). Use Context to share across stats and list components.
➜ Use useMemo to compute streaks, completion rates, and progress percentages without recalculating on every keystroke.
➜ Use useCallback to memoize the logHabit and deleteHabit functions passed to memoized child components.
➜ Use useRef to store the previous week's completion rate for comparison (without re-rendering).
➜ Wrap your habit list items with React.memo.
➜ Implement an Error Boundary to catch failures in the chart/stats component and show a fallback.
➜ Use createPortal to render a quick-add modal that floats above the dashboard.
➜ Use dynamic routing: /goals/:id to view a specific goal's detailed history via useParams.
When you are done,
💥 Share your solutions,
💥 invite a friend,
and as always —
💥 stay well, stay curious, and stay coding ✌️
✍️ Uncontrolled Components
You learned controlled components (state drives the input). Uncontrolled components let the DOM handle the input's value; you just read it via ref.
function UncontrolledForm() {
const nameRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
alert(nameRef.current.value); // Read value directly from DOM
};
return (
<form onSubmit={handleSubmit}>
<input ref={nameRef} defaultValue="Megersa" />
<button type="submit">Submit</button>
</form>
);
}
When to use: Simple forms where you don't need live validation per keystroke. It's less code but less control.
---
Part 4 --- Stability & Tooling
🚨 Error Boundaries --- Catching Crashes
If a component crashes, the whole React app unmounts (blank screen). Error Boundaries catch JavaScript errors in their child tree and display a fallback UI.
Note: Only works in class components (but you can use libraries like react-error-boundary for functions).
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log("Log error to service:", error);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong. Please refresh.</h1>;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<RiskyComponent />
</ErrorBoundary>
Analogy: Error Boundaries are like circuit breakers in your house. Instead of the whole house (app) going dark when one outlet (component) shorts, the breaker just cuts that one circuit.
---
💤 Suspense & Lazy Loading --- Code Splitting
Why load all your JavaScript at once? With React.lazy, you can load components only when they are needed (e.g., the About page only loads when the user clicks "About").
import { lazy, Suspense } from "react";
// This component will be loaded dynamically
const About = lazy(() => import("./pages/About"));
function App() {
return (
<div>
<Suspense fallback={<div>Loading page...</div>}>
<About />
</Suspense>
</div>
);
}
Analogy: Lazy loading is like a buffet. Instead of putting every dish on your plate at once (initial load), you go back to the buffet table (server) only when you want the dessert (new page).
---
🧰 Legacy Patterns (HOCs & Render Props)
Before hooks existed, we used these patterns. You might see them in older codebases.
Higher-Order Component (HOC): A function that takes a component and returns a new component with extra props.
function withAuth(Component) {
return function AuthenticatedComponent(props) {
const [user] = useContext(UserContext);
if (!user) return <p>Please login</p>;
return <Component {...props} user={user} />;
};
}
Render Props: A prop that is a function returning JSX.
<DataFetcher url="/users">
{(data) => <div>{data.map(...)}</div>}
</DataFetcher>
Pro Tip: Hooks (useContext, useEffect) replace both of these in modern React. Just know what they are when reading legacy code!
---
🛠️ React DevTools & StrictMode
React DevTools (browser extension):
· Inspect component trees (props, state, hooks).
· Profile performance to see which components re-render.
· Highlight updates to track unnecessary renders.
StrictMode (wrapped in main.jsx):
· Runs extra checks in development (e.g., detects unsafe lifecycles, warns about legacy refs).
· Important: It double-invokes effects in dev to help you catch bugs (don't panic, it's just a test!).
<React.StrictMode>
<App />
</React.StrictMode>Part 2 --- Performance Optimizations
React is fast, but unnecessary re-renders can slow you down. Here’s how to stop them.
🔹 React.memo --- Component Caching
React.memo is a higher-order component. It prevents a component from re-rendering if its props haven't changed.
jsx
// Without memo: re-renders every time parent re-renders.
const ExpensiveComponent = ({ data }) => {
console.log("Rendering!");
return <div>{data}</div>;
};
// With memo: only re-renders if 'data' changes.
const MemoizedComponent = React.memo(ExpensiveComponent);
Warning: Memoization isn't free. Use it only for components that re-render often with the same props.
---
🔹 useCallback --- Memoizing Functions
When you pass a function as a prop, it gets re-created on every render. This breaks React.memo because the prop looks different every time.
jsx
// ❌ Bad: Creates a new function every render
function Parent() {
const handleClick = () => console.log("clicked");
return <Child onClick={handleClick} />;
}
// ✅ Good: useCallback caches the function
function Parent() {
const handleClick = useCallback(() => {
console.log("clicked");
}, []); // Empty array = never changes
return <Child onClick={handleClick} />;
}
Analogy: useCallback is like giving someone a permanent business card. Without it, you hand them a new one every time they see you (pointless).
---
🔹 useTransition --- Non-Urgent Updates
Sometimes state updates cause lag (e.g., filtering a giant list while typing). useTransition lets you mark certain updates as "low priority" so they don't block the UI.
jsx
import { useState, useTransition } from "react";
function SearchPage() {
const [query, setQuery] = useState("");
const [filteredList, setFilteredList] = useState([]);
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
const value = e.target.value;
setQuery(value); // Urgent update (typing)
startTransition(() => {
// Low priority update (filtering large array)
const results = hugeList.filter(item => item.includes(value));
setFilteredList(results);
});
};
return (
<div>
<input value={query} onChange={handleChange} />
{isPending && <p>Loading results...</p>}
</div>
);
}
---
Part 3 --- DOM & UI Mastery
🚪 Portals --- Rendering Outside the Parent
Sometimes you need to render something outside the root div (e.g., modals, tooltips, dropdowns) to avoid CSS clipping or z-index issues.
ReactDOM.createPortal lets you render a component anywhere in the DOM.
jsx
import { createPortal } from "react-dom";
function Modal({ children, isOpen }) {
if (!isOpen) return null;
// Render this modal inside the "modal-root" div instead of the parent tree
return createPortal(
<div className="modal-overlay">
<div className="modal">{children}</div>
</div>,
document.getElementById("modal-root") // Must exist in index.html
);
}
Analogy: Portals are like walkie-talkies. Even though you're in one room (parent component), you broadcast your message (modal UI) to another room (modal-root) seamlessly.
---
🪞 forwardRef & useImperativeHandle --- Advanced Refs
Sometimes you need to access a DOM element inside a child component. forwardRef lets the parent pass a ref down.
jsx
// Child component
const FancyInput = forwardRef((props, ref) => {
return <input ref={ref} className="fancy" {...props} />;
});
// Parent component
function Parent() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus(); // Focusing the child's input
}, []);
return <FancyInput ref={inputRef} />;
}
useImperativeHandle lets you limit what the parent can do with the ref (like exposing only focus and clear).
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = ""; }
}));
return <input ref={inputRef} />;
});🌟 Week 9 Day 4 --- Advanced React: Context, Performance & Real-World Patterns
Hello campers 💙
Today we’ll tackle the challenges every large app faces:
· Global state (without drilling props through 10 levels)
· Advanced state logic (like a spreadsheet for your data)
· Custom reusable logic (your own hooks)
· Performance (stop wasted re-renders)
· Portal modals, Error Boundaries, Lazy Loading, and more.
Let’s dive in!
Part 1 --- State Management Deep Dive
⚠️ The Prop Drilling Problem
Remember lifting state up? It works, but what if your component tree is 5 levels deep?
<App>
<Layout>
<Sidebar>
<UserMenu>
<Avatar user={user} /> {/* user had to travel all the way down */}
</UserMenu>
</Sidebar>
</Layout>
</App>
Passing user through components that don’t even use it is called prop drilling. It’s messy and hard to refactor.
Analogy: Like giving a message to a receptionist, who gives it to a manager, who gives it to a team lead, just to reach the developer. Waste of time.
🧠 Context API --- The Solution
Context provides a way to share data across the entire component tree without passing props manually.
Steps to Use Context
1. Create the Context
import { createContext, useContext } from "react";
const UserContext = createContext();
2. Provide the Context (wrap your parent)
function App() {
const [user, setUser] = useState({ name: "Megersa" });
return (
<UserContext.Provider value={{ user, setUser }}>
<Dashboard />
</UserContext.Provider>
);
}
3. Consume the Context (in any child)
function Avatar() {
const { user } = useContext(UserContext);
return <h1>{user.name}</h1>;
}
No more drilling! 🎉
Analogy: Context is like a company-wide announcement system. Instead of whispering down the hallway (props), you broadcast it to everyone who cares (useContext).
⚙️ useReducer --- Complex State Logic
useState is great for simple data (strings, numbers). But when you have complex state with multiple sub-values or transitions (e.g., "ADD_ITEM", "REMOVE_ITEM", "UPDATE_TOTAL"), useReducer is your friend.
Basic Syntax
import { useReducer } from "react";
// 1. Define a reducer function
function cartReducer(state, action) {
switch (action.type) {
case "ADD":
return { ...state, count: state.count + 1 };
case "REMOVE":
return { ...state, count: state.count - 1 };
default:
return state;
}
}
function Cart() {
// 2. useReducer returns [state, dispatch]
const [state, dispatch] = useReducer(cartReducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "ADD" })}>+</button>
<button onClick={() => dispatch({ type: "REMOVE" })}>-</button>
</div>
);
}
Analogy: useState is a light switch (on/off). useReducer is a TV remote—lots of buttons (actions) that change the screen (state) in predictable ways.
🛠️ Custom Hooks --- Reusable Logic
If you find yourself repeating logic across components (e.g., fetching data, tracking window size, managing local storage), extract it into a Custom Hook.
Rules:
· Must start with use (e.g., useFetch).
· Can use other hooks inside (useState, useEffect, useContext).
Example: useFetch
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => { setData(data); setLoading(false); })
.catch(err => { setError(err); setLoading(false); });
}, [url]);
return { data, loading, error };
}
// Usage in any component
function Users() {
const { data, loading, error } = useFetch("https://api.example.com/users");
if (loading) return <p>Loading...</p>;
return <div>{data.map(user => <p key={user.id}>{user.name}</p>)}</div>;
}🧩 Week 9 Day 3 Challenges
Challenge 1: Movie Explorer App
Build a small multi-page movie app.
Requirements:
➜Create pages:
Home
Movies
MovieDetails
➜Use React Router DOM
➜Add navigation using Link or NavLink
➜Store movie data in an array or fetch from an API
➜Render movie cards using .map()
Clicking a movie should navigate to:
/movies/:id
➜Use useParams to display selected movie details
➜Create a reusable Card component using props.children
Challenge 2: Travel Destination Planner
Build a travel destinations app.
Requirements:
➜Create components:
Navbar
DestinationList
DestinationDetails
➜Use routing for pages
➜Add at least 5 destinations
➜Clicking a destination opens:
/destinations/:id
➜Use useNavigate for a “Go Back” button
➜Lift state up to parent component for selected region filtering
➜Use props.children for reusable layout wrappers
Challenge 3: Music Artist Dashboard
Build a music artist dashboard.
Requirements:
➜Create pages:
Home
Artists
ArtistProfile
➜Use dynamic routes:
/artists/:id
➜Display:
artist name
genre
albums
➜Use .map() to render artist list
➜Use useParams for profile page
➜Add active navigation styling using NavLink
➜Create reusable Section wrapper component using props.children
Lift search state up so multiple components can access filtered artists
When you are done,
💥 Share your solutions,
💥 invite a friend,
and as always —
💥 stay well, stay curious, and stay coding ✌️
➡ Dynamic Routes
Routes that capture variable parts of the URL, like /users/1, /users/42.
Define with a colon:
<Route path="/users/:id" element={<User />} />
Inside the User component, use useParams to grab the id:
import { useParams } from "react-router-dom";
function User() {
const { id } = useParams();
return <h1>User ID: {id}</h1>;
}
This lets you show different user profiles using the same component.
➡ useNavigate
A hook to change routes programmatically from JavaScript.
const navigate = useNavigate();
// After login:
navigate("/dashboard");
// Or go back:
navigate(-1);
Useful after form submissions, logins, or any action where you need to redirect without a link click.
➜Mental Model of Routing
React Router watches the URL. When it changes, it renders the matching component — no full page refresh. It feels instant.
Real App Structure
src/
├── components/ # reusable: Button, Card, Navbar
├── pages/ # full screens: Home, About, Profile
├── App.jsx
└── main.jsx
Pages are entire views that match a route; components are smaller pieces reused across pages. This keeps your project clean and easy to navigate.Week 9 Day 3 — Component Composition & Routing
Hello campers ❤
Today we’ll learn how React applications are organized like real systems.
React applications are built from small reusable pieces connected together.
Part 1 — Component Composition
Component Composition
Composition means combining smaller components to build larger UI structures. You split your UI into pieces like <Navbar />, <Card />, <Button /> and then nest them inside each other. For example:
function Dashboard() { return ( <div> <Sidebar /> <MainContent /> </div> ); }This keeps code clean, reusable, and easy to scale — just like building with LEGO blocks. ❌ Beginner Mistake Putting everything inside one huge component (e.g., 500 lines in App) makes it messy, hard to debug, and impossible to reuse. ✅ Better Approach Break UI into pieces, each with one responsibility: App ├── Navbar ├── Sidebar ├── Feed └── Footer Thinking in Components Before coding, ask “What parts repeat?” Those become reusable components. Example: instead of writing <h2>John</h2><h2>Sarah</h2> twice, create:
function UserCard({ name }) { return <h2>{name}</h2>; } // Then reuse: <UserCard name="John" /> <UserCard name="Sarah" /> This prevents duplication and makes your app modular and predictable. ➜Why Composition Matters Because real apps grow. Composition gives you readability, maintainability, scalability, and reusability. ➜ Shared State Problem Two sibling components (like SearchBar and ProductList) often need the same data but can’t talk directly. Without a solution, updating SearchBar won’t filter ProductList. Example:
<SearchBar /> {/* wants to update search term */}
<ProductList /> {/* wants to read search term */}
➜ Lifting State Up
Move shared state to the closest common parent (here, App). Parent holds useState, passes data and setter functions down via props.
function App() {
const [search, setSearch] = useState("");
return (
<>
<SearchBar search={search} setSearch={setSearch} />
<ProductList search={search} />
</>
);
}
Now SearchBar calls setSearch and ProductList reads search — single source of truth, both stay synced. Analogy: one shared fridge instead of each person having fake copies.
➜ props.children
A special prop that lets you pass JSX content inside a component’s tags. Inside the wrapper, you render {props.children}. Example:
function Card(props) {
return <div className="card">{props.children}</div>;
}
// Usage – different content, same wrapper:
<Card><h1>Hello</h1></Card>
<Card><button>Buy</button></Card>
This makes wrapper components reusable for any inner content.
➢ Part 2 — Routing
➡Routing
Routing determines which component to show for a specific URL. You define routes like /home → Home component, /about → About. Without routing, your React app is just one page; routing turns it into a multi‑page experience without full reloads.
➡ React Router DOM
The standard library for routing in React. Install with:
npm install react-router-dom
Then wrap your app with <BrowserRouter> in main.jsx so React can track URLs. React itself has no built‑in routing — this library fills that gap.
React Router DOM v6 – main tools
🔹 BrowserRouter – Wraps your entire app to enable routing.
import { BrowserRouter } from "react-router-dom";
<BrowserRouter><App /></BrowserRouter>
🔹 Routes & Route – Define which component renders for which path.
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
🔹 Link – Navigation without page reload (replaces <a>).
<Link to="/about">About</Link>
Regular <a> refreshes the whole page and loses state — Link keeps your app fast.
🔹 NavLink – Same as Link but adds active styling automatically.
<NavLink to="/about" className={({ isActive }) => isActive ? "active" : ""}>
About
</NavLink>
Perfect for navigation bars where the current page should look different.CommonJS Vs ES Modules
JavaScript has two main module systems: CommonJS and ES Modules.
CommonJS is the older system, built for Node.js. It uses
require() to load a module and module.exports to share code. When you write const fs = require('fs'), Node reads the file right away, line by line. This is synchronous, meaning it waits for each module to load before moving to the next line. CommonJS works well on the server because files are on your local disk and load quickly. Many old Node projects still use it, and you don't need any special settings.
ES Modules are the newer, official standard for JavaScript. They work in both modern browsers and Node.js (with "type": "module" in package.json or using .mjs files). Instead of require(), you write import { something } from './file.js' and export your code. ES Modules load asynchronously, so they can fetch multiple files at once without blocking. This makes them better for web pages and large applications. They also allow tools to remove unused code, a feature called tree shaking, which keeps your final bundle small.
The big difference between them is where and how they run. CommonJS is synchronous and works out of the box in Node, while ES Modules are asynchronous and work in both browsers and Node with a little setup. CommonJS uses require() and module.exports; ES Modules use import and export. For new projects, ES Modules are the better choice because they follow the standard and will work everywhere. But you still see CommonJS everywhere, especially in older Node code and many npm packages.
stay well, stay curious, and stay coding ✌️Repost from Bytephilosopher
Today I had a meeting with a senior Google developer who has worked there for more than 20 years, both as a permanent employee and freelancer. It was such an amazing experience, and I got a lot of valuable insights from him.
Here are some life principles and lessons I learned:
1. Stay fit and take care of your health. At the end of the day, health matters the most.
2. Focus on building real skills first. Don’t just follow whatever trend the world is chasing. Work on something you truly enjoy, something you can spend hours on like it’s a game. Read books, especially research papers. If you are a junior developer, learn the fundamentals deeply. Use AI wisely to understand things from the ground level.
3. Communication skills are just as important as technical skills. Learn how to explain and present your knowledge. These days, your online presence matters a lot more than just a resume. Build visibility through platforms like GitHub and by sharing your work online.
Also, attend workshops and meetups. But don’t just attend. make sure you connect with at least one person and keep in touch with them.
4. Have a spiritual life. Whether you are religious or not, always try to be good to others. You never know when your kindness will come back to help you.
Another important point was this:
Build projects that solve your own problems or local problems around you. It’s easier to understand problems you personally face. Then think about how those solutions can scale internationally.
And about AI:
Use AI as a mentor, not as something to completely depend on. Learn the basics well and use AI to simplify your learning and productivity.
Finally, being a good developer means being a lifelong learner. Technology changes fast, and you must keep updating yourself. He started learning during the COBOL and FORTRAN era, and he still adapts to modern technologies today. So keep learning, keep building, and prepare yourself for the international market.
Visibility matters. Real projects matter. Continuous learning matters.
@byte_philosopher
🧩 Week 9 Day 2 Challenges
Challenge 1: Student Registration App
➢Build a small app where users can register students.
Requirements:
➛Create a form with:
name
age
course
➛Use useState for all inputs
On submit:
➢prevent page refresh
➢add student to a displayed list
➢Use .map() to render all students
➢Show total students registered
➢Add conditional message:
➢if no students → show "No students yet"
Challenge 2: Product Search Dashboard
Build a product list dashboard.
Requirements:
➛Create an array of at least 8 products
➛Render them using .map()
➛Add search input
➛Use onChange to filter products by name
➛Use conditional rendering:
➛if no product matches → show "No products found"
➛Use useMemo to optimize filtered results
➛Add a button that focuses search input using useRef
Challenge 3: User Fetch + Profile Viewer
Build a user viewer app.
Requirements:
➛Fetch users from: https://jsonplaceholder.typicode.com/users
➛Use useEffect
➛Display:
name
email
company
➛Add loading state
Add button:
➤show/hide users
➤Add input field to search users by name
➤Use conditional rendering
➤Add cleanup function inside useEffect
➤Use keys properly when rendering list
When you are done,
💥 Share your solutions,
💥 invite a friend,
and as always —
💥 stay well, stay curious, and stay coding ✌️
➤ useEffect
useEffect handles side effects – operations that interact with the outside world or that React cannot manage during rendering. Examples: fetching data, reading localStorage, setting timers, or manually changing the DOM.
useEffect takes two arguments: a function (the effect) and a dependency array. The effect runs after the component renders (or commits to the screen). The dependency array tells React when to re‑run the effect:
Basic Syntax
useEffect(() => { console.log("Mounted"); }, []);Dependency Array ➛Empty [] Runs once. ➛With dependency [count] Runs when count changes. ➛No dependency Runs every render. Analogy Dependency array = trigger list. Like security sensors. Only activates when chosen values change. ➛Cleanup Function Used when component leaves.
useEffect(() => { const timer = setInterval(() => { console.log("Running"); }, 1000); return () => { clearInterval(timer); }; }, []);Why? Prevent memory leaks. ➤ Fetching API Data Fetching data is a classic side effect, so it belongs inside useEffect (usually with an empty dependency array to run once on mount). While fetching, you typically manage three states: data, loading, and error. This pattern gives users feedback and handles failures gracefully.
useEffect(() => { fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(data => console.log(data)); }, []);
Axios Version
Install:
npm install axios
Usage
import axios from "axios";
useEffect(() => {
axios.get("https://jsonplaceholder.typicode.com/users")
.then(res => console.log(res.data)); }, []);
➤ useRef
useRef creates a mutable object with a .current property. Unlike state, changing .current does not trigger a re‑render. This makes useRef ideal for:
· Accessing DOM nodes directly (e.g., focusing an input, measuring size).
· Storing values that persist across renders but shouldn’t cause re‑renders (e.g., interval IDs, previous values).
const inputRef = useRef();
Access DOM
<input ref={inputRef} /> <button onClick={() => inputRef.current.focus()}> Focus </button>Analogy useRef = sticky note. Stores info quietly. No UI update. ➤ useMemo useMemo caches the result of a computation. It only recomputes when one of its dependencies changes. Use it for expensive calculations (e.g., filtering large arrays, complex math) to avoid doing unnecessary work on every render.
const result = useMemo(() => { return heavyCalculation(data); }, [data ]);Why? Avoid unnecessary recalculation. Analogy Like saving previous math answer. No need to solve again.
