-
John Doe - 24 Apr, 2026
React Hooks Patterns You Should Know in 2026
React hooks transformed how we write components. But knowing useState and useEffect is just the beginning. These are the patterns that separate good React code from great React code. The Problem with Scattered Logic Before hooks, stateful logic was locked inside class components or prop-drilled through component trees. Hooks let you extract and reuse logic cleanly. Here's what messy looks like: function UserProfile({ userId }: { userId: string }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { setLoading(true); fetch(`/api/users/${userId}`) .then(r => r.json()) .then(data => { setUser(data); setLoading(false); }) .catch(err => { setError(err); setLoading(false); }); }, [userId]); if (loading) return <Spinner />; if (error) return <Error message={error.message} />; return <div>{user.name}</div>; }There's nothing wrong with this, but the data-fetching logic is tangled with the UI. Let's fix that. Custom Hooks Extract the logic into a custom hook — any function starting with use: function useFetch<T>(url: string) { const [state, setState] = useState<{ data: T | null; loading: boolean; error: Error | null; }>({ data: null, loading: true, error: null }); useEffect(() => { let cancelled = false; setState(s => ({ ...s, loading: true })); fetch(url) .then(r => r.json()) .then(data => { if (!cancelled) setState({ data, loading: false, error: null }); }) .catch(error => { if (!cancelled) setState({ data: null, loading: false, error }); }); return () => { cancelled = true; }; }, [url]); return state; }// Usage — clean! function UserProfile({ userId }: { userId: string }) { const { data: user, loading, error } = useFetch<User>(`/api/users/${userId}`); if (loading) return <Spinner />; if (error) return <Error message={error.message} />; return <div>{user!.name}</div>; }The cancelled flag prevents state updates on unmounted components — always important for async effects. useReducer for Complex State When multiple pieces of state update together, useReducer is cleaner than multiple useState calls: type State = { items: CartItem[]; total: number; coupon: string | null; };type Action = | { type: 'ADD_ITEM'; item: CartItem } | { type: 'REMOVE_ITEM'; id: string } | { type: 'APPLY_COUPON'; code: string } | { type: 'CLEAR' };function cartReducer(state: State, action: Action): State { switch (action.type) { case 'ADD_ITEM': { const items = [...state.items, action.item]; return { ...state, items, total: computeTotal(items, state.coupon) }; } case 'REMOVE_ITEM': { const items = state.items.filter(i => i.id !== action.id); return { ...state, items, total: computeTotal(items, state.coupon) }; } case 'APPLY_COUPON': return { ...state, coupon: action.code, total: computeTotal(state.items, action.code) }; case 'CLEAR': return { items: [], total: 0, coupon: null }; } }function Cart() { const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0, coupon: null }); return ( <button onClick={() => dispatch({ type: 'CLEAR' })}> Clear cart ({state.items.length} items) </button> ); }Reducers are pure functions — easy to test, easy to reason about. Move complex state transitions here and keep your components dumb.useCallback and useMemo: When They Matter A common misunderstanding: these hooks are not free performance wins. They have a cost too. Use them selectively. useMemo — memoize expensive calculations: function FilteredList({ items, filter }: Props) { // Only re-compute when items or filter changes const filtered = useMemo( () => items.filter(item => item.name.includes(filter)).sort(/* ... */), [items, filter] ); return <List items={filtered} />; }useCallback — stabilize function references passed to child components: function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { console.log('clicked'); }, []); // stable reference return ( <> <button onClick={() => setCount(c => c + 1)}>Count: {count}</button> <MemoizedChild onClick={handleClick} /> </> ); }const MemoizedChild = React.memo(({ onClick }: { onClick: () => void }) => { console.log('child rendered'); return <button onClick={onClick}>Click</button>; });The useRef Pattern for Intervals A surprisingly tricky use case — you want an interval that always has access to the latest state: function useInterval(callback: () => void, delay: number | null) { const savedCallback = useRef(callback); useEffect(() => { savedCallback.current = callback; }, [callback]); useEffect(() => { if (delay === null) return; const id = setInterval(() => savedCallback.current(), delay); return () => clearInterval(id); }, [delay]); }// Usage function Timer() { const [count, setCount] = useState(0); useInterval(() => setCount(c => c + 1), 1000); return <div>Count: {count}</div>; }Closing Thought The best custom hook is one you never have to explain. If a component is doing too many things, extract a hook. If two components share the same logic pattern, extract a hook. The rule: if it's not about rendering, it probably belongs in a hook.
-
John Doe - 18 Apr, 2026
Docker for Developers: From Zero to Production
Docker changed how we ship software. Before containers, deploying an application meant wrestling with environment differences, missing dependencies, and the classic "it works on my machine" problem. Let's fix that. What is Docker? Docker packages your application and all its dependencies into a container — a lightweight, isolated unit that runs identically everywhere. The key insight: containers share the host OS kernel, making them far lighter than virtual machines. Host Machine ├── Docker Engine │ ├── Container A (Node.js app) │ ├── Container B (PostgreSQL) │ └── Container C (Redis) └── Shared OS KernelCore Concepts Images vs ContainersImage: A read-only blueprint (like a class in OOP) Container: A running instance of an image (like an object)# Pull an image from Docker Hub docker pull node:20-alpine# Run a container from it docker run -it node:20-alpine node --versionWriting a Dockerfile A Dockerfile defines how to build your image: # Use official Node.js LTS image FROM node:20-alpine# Set working directory WORKDIR /app# Copy dependency files first (layer caching optimization) COPY package*.json ./ RUN npm ci --only=production# Copy source code COPY . .# Expose port EXPOSE 3000# Start command CMD ["node", "server.js"]Build and run it: docker build -t my-app:latest . docker run -p 3000:3000 my-app:latestMulti-Stage Builds This is one of the most powerful Docker patterns for production. Build artifacts in one stage, copy only what you need into a lean final image: # Stage 1: Build FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build# Stage 2: Production FROM node:20-alpine AS production WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY --from=builder /app/dist ./dist EXPOSE 3000 CMD ["node", "dist/server.js"]The final image only contains production dependencies and compiled output — no dev tools, no source TypeScript. Images can shrink from 1GB+ to under 150MB.Docker Compose docker-compose.yml orchestrates multi-container applications: services: app: build: . ports: - "3000:3000" environment: DATABASE_URL: postgres://user:password@db:5432/mydb REDIS_URL: redis://cache:6379 depends_on: db: condition: service_healthy cache: condition: service_started db: image: postgres:16-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydb volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d mydb"] interval: 5s timeout: 5s retries: 5 cache: image: redis:7-alpine volumes: - redis_data:/datavolumes: postgres_data: redis_data:Start everything with a single command: docker compose up -d # start in background docker compose logs -f # stream logs docker compose down # stop and remove containersEssential Commands # Images docker images # list local images docker rmi my-app:latest # remove an image docker image prune # clean dangling images# Containers docker ps # running containers docker ps -a # all containers docker exec -it <id> sh # open shell in running container docker logs -f <id> # stream container logs docker stop <id> # graceful stop docker rm <id> # remove stopped container# System docker system prune -a # nuclear cleanup docker stats # live resource usageKey Best Practices Use .dockerignore to exclude node_modules, .git, logs, and local env files — keeps your build context small and images clean. Pin image versions — use node:20.18-alpine not node:latest to ensure reproducible builds. Run as non-root — add USER node before your CMD to follow the principle of least privilege. One process per container — don't run nginx + Node.js in a single container. Use Docker Compose instead. Wrapping Up Once Docker clicks, you won't want to develop without it. Your local environment exactly mirrors production, onboarding new developers takes minutes not hours, and you can spin up any service without installing it globally. That's the deal.
-
John Doe - 10 Apr, 2026
Getting Started with TypeScript: A Practical Guide
TypeScript has become the de facto standard for large-scale JavaScript applications. In this post, I'll walk through the key concepts you need to be productive with it immediately. Why TypeScript? The core value proposition is catching bugs at compile time rather than runtime. When you're working on a large codebase, the ability to have your editor tell you when something is wrong — before you even run the code — is a massive productivity boost. // JavaScript — this will fail silently at runtime function greet(user) { return `Hello, ${user.name.toUpperCase()}`; } greet(null); // 💥 TypeError at runtime// TypeScript — caught immediately function greet(user: { name: string }) { return `Hello, ${user.name.toUpperCase()}`; } greet(null); // ❌ Compile error: Argument of type 'null' is not assignableThe Basics Type Annotations You can annotate variables, function parameters, and return types: const age: number = 28; const name: string = "Dev"; const isActive: boolean = true;function add(a: number, b: number): number { return a + b; }TypeScript can often infer types, so you don't always need to be explicit: const count = 42; // inferred as number const message = "hello"; // inferred as stringInterfaces and Types Interfaces are the bread and butter of TypeScript's type system: interface User { id: number; name: string; email: string; role: 'admin' | 'editor' | 'viewer'; createdAt: Date; }function displayUser(user: User): string { return `${user.name} (${user.role})`; }Tip: Prefer interface for object shapes that might be extended, and type for unions, intersections, and aliases.Generics Generics let you write reusable code that works with multiple types: function first<T>(array: T[]): T | undefined { return array[0]; }const num = first([1, 2, 3]); // inferred as number | undefined const str = first(['a', 'b']); // inferred as string | undefinedPractical Patterns Optional Chaining and Nullish Coalescing TypeScript pairs beautifully with modern JS features: interface Config { timeout?: number; retries?: number; }function connect(config?: Config) { const timeout = config?.timeout ?? 5000; const retries = config?.retries ?? 3; // ... }Discriminated Unions A pattern for modeling state machines and variant types: type Result<T> = | { status: 'success'; data: T } | { status: 'error'; message: string } | { status: 'loading' };function handleResult<T>(result: Result<T>) { switch (result.status) { case 'success': console.log(result.data); // TypeScript knows data exists here break; case 'error': console.error(result.message); break; case 'loading': console.log('Loading...'); break; } }Getting Started Install TypeScript in any project with: npm install -D typescript npx tsc --initThe tsconfig.json file controls the compiler. A reasonable starting config: { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "noUncheckedIndexedAccess": true } }Enable strict: true from the start — it enables all the strict checks that catch the most bugs. Conclusion TypeScript's learning curve is gentle if you start with basics and gradually adopt more advanced patterns. The tooling support — especially in VS Code — makes the experience excellent. Start adding TypeScript to your next project and you'll wonder how you lived without it.
How to make toys from old Olarpaper
Nemo vel ad consectetur namut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod. Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius! Creative Design Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!
Become a morning person with the help of alarm clock
Almost every day for the past nine or so months has felt like March 13, and that can sometimes make it difficult to want to wake up for the day ahead of you. To make a morning person out of you, the wake-up light simulates the sunrise to gradually ease you awake. This allows you to wake up more naturally rather than being jolted awake by the default iPhone alarm sound, which honestly triggers my fight or flight response. Creative Design Nam ut rutrum ex, venenatis sollicitudin urna. Aliquam erat volutpat. Integer eu ipsum sem. Ut bibendum lacus vestibulum maximus suscipit. Quisque vitae nibh iaculis neque blandit euismod.Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!Lorem ipsum dolor sit amet consectetur adipisicing elit. Nemo vel ad consectetur ut aperiam. Itaque eligendi natus aperiam? Excepturi repellendus consequatur quibusdam optio expedita praesentium est adipisci dolorem ut eius!