Whether you need a high-performance web application, full-stack architecture advisory, or an engineer who ships with urgency and care.
Jump directly on my calendar to talk about goals, timeline, and fit.
The useWindowSize hook in react is very useful when you require javascript to get the size of the device and render the contents as required. It very useful when working with various sizes of devices. It can be useful when working with responsive designs. The following code demonstrates how one can implement the useWindowSize hook in their next project.
You can use the hook in your required tsx/jsx file as follows:
You can use the above code or modify to your own use in react to handle contents in various devices.
Explore more articles on software architecture, frontend craftsmanship, and backend engineering.

Pattern problems are great for practicing loops and logical thinking in programming. We will discuss and try out some of the basic pattern problems.
Right Triangle
for (let i = 0; i < 5; i++) {
let pattern = "";
for (let j = 0; j < i; j++) {
pattern += "*";
}
console.log(pattern);
}Output:
*
**
***
****
*****Left Triangle
for (let i = 5; i > 0; i--) {
let pattern = "";
for (let j = i; j > 0; j--) {
pattern += "*";
}
console.log(pattern);
}Output:
*****
****
***
**
*Pyramid
const n = 5;
for (let i = 0; i < n; i++) {
let pattern = "";
for (let j = 0; j < n - i; j++) {
pattern += " ";
}
for (let k = 0; k < i; k++) {
pattern += "*";
}
for (let l = i - 1; l > 0; l--) {
pattern += "*";
}
console.log(pattern);
}Output:
*
***
*****
*******Diamond
const n = 5;
for (let i = 1; i <= n; i++) {
let pattern = "";
for (let j = 1; j <= n - i; j++) {
pattern += " ";
}
for (let k = 1; k <= 2 * i - 1; k++) {
pattern += "*";
}
console.log(pattern);
}
for (let i = n - 1; i >= 1; i--) {
let pattern = "";
for (let j = 1; j <= n - i; j++) {
pattern += " ";
}
for (let k = 1; k <= 2 * i - 1; k++) {
pattern += "*";
}
console.log(pattern);
}Output:
*
***
*****
*******
*********
*******
*****
***
*
useEffect hook is one of the most powerful and misunderstood hooks. It handles side effects, runs after rendering, replaces lifecycle methods, and synchronizes your component with external systems such as APIs, subscriptions, DOM manipulation, timers, or logging. However, as your application grows, useEffect can become a source of bugs, race conditions, duplicate network calls, and performance regressions if not used correctly. This blog covers useEffect usage, best practices, patterns, and pitfalls that even experienced developers run into.
React's render function must be pure meaning it cannot modify variables outside its scope, perform I/O, or change the DOM. Anything that breaks purity is a side effect, for example:
Fetching data
Subscribing to WebSockets
Setting timers
Writing to localStorage
Manipulating the DOM
Syncing app state with URL or props
useEffect allows these operations in a safe, predictable way.
useEffect Runs After Render (Not During Render)
useEffect(() => {
console.log("Runs after render");
});This guarantees:
The DOM is updated before the effect runs.
Effects never block rendering.
Effects run asynchronously.
The dependency array controls when the effect should re-run.
Run on every render
useEffect(() => {
console.log("runs on every render");
});Run only once (on mount)
useEffect(() => {
console.log("mounted");
}, []);Equivalent to componentDidMount.
Run when dependencies change
useEffect(() => {
console.logUser changed: ${userId});
}, [userId]);Equivalent to componentDidUpdate(userId).
Run on unmount (cleanup)
useEffect(() => {
return () => console.log("unmounted");
}, []);Equivalent to componentWillUnmount.
Cleanup is essential for:
unsubscribing event listeners
aborting fetch requests
closing WebSockets
clearing intervals
canceling timeouts
useEffect(() => {
const id = setInterval(() => {
console.log("tick");
}, 1000);
return () => clearInterval(id); // cleanup
}, []); Every time the effect re-runs, cleanup executes before running the next effect.
This code causes an infinite loop
useEffect(() => {
setCount(count + 1);
});Because setCount changes state -> triggers re-render -> triggers effect -> repeats forever.
Fix using dependencies
useEffect(() => {
setCount(count + 1);
}, []); // runs only onceBeginners often write
useEffect(() => {
fetch("/api").then(...);
}, []);This works but has problems
Cannot cancel outdated requests
Race conditions when dependency changes
Causes warnings in React Strict Mode
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch("/api", { signal: controller.signal });
const data = await res.json();
setData(data);
} catch (e) {
if (e.name !== "AbortError") console.error(e);
}
}
load();
return () => controller.abort();
}, []); Use useEffect Only for Side Effects
Not everything requires an effect.
Bad (overusing effects)
useEffect(() => {
setFiltered(users.filter(u => u.active));
}, [users]);Better (derive inside render)
const filtered = users.filter(u => u.active); Effects should not calculate derived state, they only handle side effects.
Every value used inside an effect must appear in its dependency array.
Example: Missing dependency
useEffect(() => {
console.log(user.name); // depends on user
}, []); React will warn you.
Correct
useEffect(() => {
console.log(user.name);
}, [user]);Consider:
useEffect(() => {
const id = setInterval(() => {
console.log(count); // stale value!
}, 1000);
return () => clearInterval(id);
}, []);Here, count is always the initial value.
Solutions
Add count as dependency (causes interval resets)
Use functional state updates
Use refs
Improved version
useEffect(() => {
const id = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(id);
}, []);componentDidMount -> useEffect(..., [])
componentDidUpdate -> useEffect(..., [deps])
componentWillUnmount -> useEffect(() => return cleanup, [])
getDerivedStateFromProps -> Not directly an effect (use memo/derived data)
Running effects too often
Fix: Use proper dependencies.
Using objects/arrays without memoization
Fix:
const options = useMemo(() => ({ limit: 10 }), []);
useEffect(() => { ... }, [options]);Fetching data incorrectly
Fix: Use AbortController or a library like SWR/React Query.
Using effects to perform calculations
Fix: Calculate inside render or use useMemo.
Why do effects run twice in React Strict Mode?
To detect unsafe side effects.
How do you avoid stale closure bugs inside effects?
Functional updates or refs.
Why must all dependencies be listed?
To maintain predictable behavior and avoid stale values.
What is the difference between an effect and layout effect?
useLayoutEffect runs before the browser paints. useEffect runs after the paint.
How do you cancel network requests inside an effect?
AbortController.
Avoid effects when:
You’re computing derived state
You can use CSS instead of JS to manipulate DOM
You’re syncing two pieces of state
Example of overkill
useEffect(() => {
setFullName(`${first} ${last}`);
}, [first, last]); Better
const fullName = `${first} ${last}`useEffect is extremely powerful, but with great power comes great responsibility. Used correctly, it allows your app to sync with the outside world safely. Used incorrectly, it creates bugs, unnecessary renders, and spaghetti logic.
Focus on
Use correct dependencies
Perform cleanups
Avoid overusing useEffect
Understand async behaviour
Prevent stale closures

React provides several powerful hooks to help developers manage state and side effects inside functional components. One of the most commonly used hooks and usually the very first one you learn is the useState hook. If you’ve ever wanted a way for your component to “remember”(in memory) something and react when it changes, this guide explains everything you need.
useState is a React hook that allows you to add a state variable to your functional component. A state variable is any piece of data that React should track over time, and whenever it changes, your component re-renders to reflect the update.
Basic Syntax
const [state, setState] = useState(initialState); This returns an array with:
state : current value
setState : a function to update that value
React remembers the state across renders, updates it when setState is called, and re-renders the component with the new value.
Let’s look at a simple example where we store and update text from an input box:
import { useState } from "react";
export default function MyComponent() {
// initial state is an empty string
const [value, setValue] = useState("");
const updateValue = (e) => { setValue(e.target.value); };
return (
<div>
<input onChange={updateValue} placeholder="Change Value" />
<p>The state value is {value}</p>
</div>
);
}What happens here?
The state variable value starts as "".
When you type into the input, updateValue runs.
setValue updates the state.
The component re-renders, showing the new value.
You can set the initial state to anything:
useState(0) // number
useState("") // string
useState(null) // null
useState([]) // array
useState({}) // object
useState(() => computeExpensive()) // lazy initializationNote: If you start with null or undefined, make sure your code handles it safely.
Two Approaches
Set state directly
Useful when new state does not depend on the previous one.
setState("next value"); Functional updates
Recommended when previous state matters.
setState(prev => prev + 1);This ensures React calculates the next state using the latest value.
React batches updates for performance, meaning calling setState does not update the value immediately. Example that does NOT work as expected:
const [count, setCount] = useState(0);
setCount(count + 1); // setCount(0 + 1)
setCount(count + 1); // setCount(0 + 1)
setCount(count + 1); // setCount(0 + 1)All three updates use the same initial value (0) because they are queued before the component re-renders. Final result is 1, not 3.
Correct version:
setCount(prev => prev + 1); // setCount(0 + 1)
setCount(prev => prev + 1); // setCount(1 + 1)
setCount(prev => prev + 1); // setCount(2 + 1)Now React uses the updated value each time. Final result is 3.
Expecting state to update immediately
Beginners often write:
setValue("new");
console.log(value); // still oldReact updates state on the next render, not instantly.
Updating state based on old value without functional update
Incorrect:
setCount(count + 1);
setCount(count + 1);Correct:
setCount(prev => prev + 1);Mutating state directly
Example:
obj.name = "Rajesh";React won’t re-render.
Correct:
setStateObj(prev => ({ ...prev, name: "John" }));Forgetting that initial state is used only once
This does NOT recalculate on every re-render:
useState(Math.random());It runs only on the first render.
Using state when a variable would suffice
Not everything needs to be stored in state. If something doesn’t need to trigger a re-render, use useRef or a normal variable.
What does useState return?
A tuple: [state, setState].
Why does React batch state updates?
For performance, multiple updates happen in one render cycle.
Why should you use a functional update?
When the next state depends on the previous one.
Can you explain why reading state immediately after setting it returns the old value?
Because setState is asynchronous and scheduled for the next render.
What is lazy initialization in useState?
Passing a function to useState: useState(() => expensiveComputation()); The function runs only on the initial render.
Why can’t we conditionally call useState?
React hooks rely on consistent order across renders. Conditional hooks break that order.
useState is simple but incredibly powerful. It lets your components store data, respond to user input, and re-render when needed. Once you understand that state updates are asynchronous and how functional updates work, you’ll write far fewer bugs and much cleaner React code.

Let's start by cloning our already made todo app. We will be testing the crud function and also checking for UI updates. Vitest is easy to get started with. Just follow along and you will begin testing your apps soon.
Add Vitest,jsdom and necessary testing libraries for UI testing to get started.
npm i -D vitest @testing-library/jest-dom @testing-library/user-event @types/jest @vitest/ui jsdomYou can additionally add the following scripts to package .json
"scripts": {
"test": "vitest",
"test:ui": "vitest --ui",
"coverage": "vitest run --coverage"
}Before testing our application, we need to set up some files to get started. Start by creating a new file test-utils that will have all the utilities for our tests.
//tests/test-utils.tsx
import { cleanup, render } from "@testing-library/react";
import { afterEach } from "vitest";
afterEach(() => {
cleanup();
});
function customRender(ui: React.ReactElement, options = {}) {
return render(ui, {
// wrap provider(s) here if needed
wrapper: ({ children }) => children,
...options,
});
}
export * from "@testing-library/react";
export { default as userEvent } from "@testing-library/user-event";
// override render export
export { customRender as render };//tests/setup.ts
import '@testing-library/jest-dom';We need now to update our Vite config to include test files.
// vite.config.ts
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
// you might want to disable it, if you don't have tests that rely on CSS
// since parsing CSS is slow
css: true,
},
})First, let's start by performing component testing. For this, we can create a test file to test our input component. We can test as many scenarios as we like. Here, we will test if the component is rendered properly and if the input can change values and update as we require. Initially, we will test to see if the component in rendered to the document.
//components/Input/Input.test.tsx
import { render, screen, userEvent } from "../../utils/test-utils";
import Input from "./Input";
test("should render the input component.", () => {
render(<Input label="Add Todo" inputProps={{}} />);
expect(screen.getByText(/Add Todo/i)).toBeInTheDocument();
expect(screen.getByRole("textbox", { name: "Add Todo" })).toBeInTheDocument();
});First, we render the component making use of @testing-library/react and we will check if the component is rendered. We can additionally check for props and values the input component should have as the props have been passed in. for this we can again make use of helper functions provided by @testing-library/react to get the component properties. Here, we test to see if the input component has the label of "Add Todo" and we also check for the input box having the name 'Add Todo'.
We can now test our input for value changes and updates.
test("should update input value on change.", async () => {
render(<Input label="Add Todo" inputProps={{}} />);
const input = screen.getByRole("textbox", { name: "Add Todo" });
expect(input).toBeInTheDocument();
await userEvent.type(input, "new todo");
expect(input).toHaveValue("new todo");
});Here, we render the input then we check if the input box is present in the document. If the input box check passes we can then type anything we want into the input box. We then check if the input has the same value as we typed.
Now we can test our addtodo functionality in the app. Continue by creating a new file AddTodo.test.tsx . We can begin by checking if the UI for the form is present in the document.
//src/AddTodo.test.tsx
import App from "./App";
import { render, screen, userEvent } from "./utils/test-utils";
test("should render the todo form.", () => {
render(<App />);
expect(screen.getByText(/Add Todo/i)).toBeInTheDocument();
expect(screen.getByRole("textbox", { name: "Add Todo" })).toBeInTheDocument();
const button = screen.getByRole("button", { name: /add/i });
expect(button).toBeInTheDocument();
});Now we can test the functionality of the add todo form. Here, we again test by rendering the App component and then check for the title of the remaining todo in the document. Then we add a new todo to the input and click on the button for adding. We then finally check if the newly added todo is also present in the UI document.
test("should add todo to the remaining todos list.", async () => {
render(<App />);
expect(screen.getByText(/Remaining Todos/i)).toBeInTheDocument();
const input = screen.getByRole("textbox", { name: /add todo/i });
expect(input).toBeInTheDocument();
await userEvent.type(input, "new todo");
const button = screen.getByRole("button", { name: /add/i });
expect(button).toBeInTheDocument();
await userEvent.click(button);
expect(screen.getByText(/new todo/i)).toBeInTheDocument();
});We successfully tested different scenarios for the todo app. We also made it possible to pass all the tests. Implement similarly in your apps now.