React fresher rounds check that you can explain the basics in your own words, build a small component on a whiteboard and talk honestly about what you made. Expect questions on JSX and fragments, function components, passing props and handling clicks, updating state without surprises, simple forms, fetching data with loading and error states, a first router setup and your college projects. It is written for final-year students, new graduates and anyone going into a first React job from an internship or a bootcamp. Read each sample answer, then say your own version out loud. Keys, effects in depth, memoisation and context are on the main React page.
Search all questions by round, difficulty and level, or save the ones you want to practice.
What it is: a JavaScript library for building user interfaces out of components.
Declarative: you describe what the screen should look like for the current data; React updates the DOM for you.
Reuse: small components like a button or a card are written once and used everywhere.
Honest limit: it's the view layer; routing and data tools usually come from other libraries or a framework.
“React is a JavaScript library for building user interfaces out of components. With plain JavaScript, I have to find elements and change them by hand every time data changes, and in a bigger page that gets messy fast, because I have to remember every place that shows that data. In React I just describe what the screen should look like for the current state, and when the state changes React works out what to update in the DOM. The other big win is reuse. I write a card or a button component once, pass it different props and use it all over the app. It's worth saying it's mainly the view layer, so things like routing usually come from another library or a framework built on React.”
Only saying React is fast or popular, with no idea of the problem it solves compared with manual DOM updates.
What it is: a syntax that looks like HTML inside JavaScript.
Build step: the browser can't read it; a tool compiles each tag into a JavaScript function call.
Differences: className not class, htmlFor not for, camelCase events like onClick, every tag closed.
Curly braces: any JavaScript expression goes inside {}, but not statements like if or for.
“JSX is a syntax that lets me write something that looks like HTML inside my JavaScript. The browser can't run it directly. The build tool, Babel or whatever Vite uses underneath, turns each tag into a normal JavaScript function call that creates a React element. Because it's really JavaScript, a few things change from HTML. I write className instead of class, because class is a keyword, and htmlFor instead of for. Event names are camelCase, like onClick, and they take a function, not a string. Every tag has to be closed, so an image is written with a self-closing slash. And inside curly braces I can put any JavaScript expression, like a variable or a map call, but not an if statement, so for conditions I use a ternary or &&.”
const name = 'Lena';
const greeting = (
<label htmlFor="email" className="title">
Hello, {name.toUpperCase()}
</label>
);
Saying JSX is HTML that the browser understands, or not knowing why it's className and not class.
Class: extends React.Component, has a render method, state in this.state, updates with this.setState.
Lifecycle: classes use methods like componentDidMount; functions use hooks such as useEffect.
Function: a plain function that takes props and returns JSX; state comes from useState.
Today: new code uses function components; classes still show up in older codebases and error boundaries.
“A class component extends React.Component, has a render method that returns JSX, keeps state in this.state and changes it with this.setState. It uses lifecycle methods like componentDidMount for things that should happen after it appears on the page. A function component is just a function that takes props and returns JSX. Since hooks came in, functions can have state with useState and side effects with useEffect, so they can do almost everything a class can, with less code and no worrying about this. In a new project I'd write function components. I still learned to read classes, though, because a lot of existing code at companies uses them, and an error boundary still has to be written as a class unless you use a small library.”
Saying function components can't have state, or not knowing class components exist in older code.
Why: JSX turns into a function call, and a function returns one value, so two siblings need a single wrapper.
Div fix: wrapping in a div works but adds an extra element that can break layouts like tables or flex rows.
Fragment: <>...</> groups children with no extra element in the DOM.
Long form: <Fragment key={id}> when it needs a key inside a list.
“Each JSX tag becomes a function call, and a component, like any function, can only return one value. Two elements side by side would be two values, so the compiler throws an error before it even runs. I could wrap them in a div, but that puts an extra element in the page, which can break a table, where a div inside a table row isn't allowed, or mess up a flex or grid layout. A Fragment fixes that. I write the empty tags, open angle bracket close angle bracket, around the two elements, and React groups them without adding anything to the DOM. If I'm returning fragments from a map, I need the long form, Fragment with a key, because the short empty tags can't take attributes.”
function Header() {
return (
<>
<h1>My Notes</h1>
<p>Everything in one place.</p>
</>
);
}
Always wrapping in an extra div without knowing a Fragment exists or why the rule is there.
Create: a build tool like Vite scaffolds it; then install packages and run the dev server.
index.html: has one empty element, usually <div id="root">.
Entry file: main.jsx finds that element and renders the App component into it.
src folder: components, styles and assets; package.json lists dependencies and scripts.
“For my own projects I use Vite. I run the create command, pick the React template, then npm install and npm run dev, and it starts a local server that reloads as I save. Older tutorials use Create React App, but the React docs no longer recommend it for new projects. Inside, index.html has one empty div with the id root. The entry file, main.jsx, finds that div with getElementById, creates a React root on it and renders my App component. From there everything is components under src, each usually in its own file. package.json lists the dependencies and the scripts like dev and build. When I run the build script, it produces a folder of plain HTML, CSS and JavaScript that I can put on any static host.”
// src/main.jsx
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
createRoot(document.getElementById('root')).render(<App />);
Having only ever edited code in an online sandbox and not knowing where the app starts or how it reaches the page.
Cause: <StrictMode> around the app, often added by the project template.
What it does: in development only, it renders components twice and runs effects, their cleanup, then the effects again.
Why: to expose code that isn't pure or effects that don't clean up.
Production: none of this happens in the production build, so it's not a bug.
“The usual cause is StrictMode. Project templates wrap the App in StrictMode in main.jsx, and in development it deliberately calls my component function twice, and runs every effect, then its cleanup, then the effect again, right after the component first appears. It's not a bug in my app, and it doesn't happen in the production build. The point is to catch mistakes early. If my component changes something outside itself while rendering, or an effect opens a connection and never closes it, running things twice makes that show up as a visible problem during development. So I wouldn't remove StrictMode to hide the double log. If an effect breaks when it runs twice, I'd fix it by adding a proper cleanup.”
Deleting StrictMode to make the double log go away without understanding what it was showing.
Single-page app: one HTML page; a router swaps the component based on the URL.
Routes: a path mapped to a component, including a dynamic segment like /products/:id.
Link: changes the URL without a full reload, so state and loaded files stay.
Params: useParams reads the id inside the product page.
“A React app is usually a single-page app, so there's one HTML page and a router decides which component to show for the current URL. I'd use React Router. I wrap the app in a BrowserRouter, then list Routes, each with a path and the element to show. For products I use a dynamic path, slash products slash colon id, and inside the product page I read the id with the useParams hook and fetch that product. For navigation I use the Link component instead of a normal anchor tag. A plain anchor makes the browser request a whole new page, so the app reloads, everything in state is lost and all the JavaScript loads again. Link just changes the URL and lets the router swap the component, so it feels instant.”
import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';
function Product() {
const { id } = useParams();
return <h2>Product {id}</h2>;
}
export default function App() {
return (
<BrowserRouter>
<nav><Link to="/">Home</Link> <Link to="/about">About</Link></nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products/:id" element={<Product />} />
</Routes>
</BrowserRouter>
);
}
Using plain anchor tags everywhere and not noticing that the whole app reloads on every click.
How && works: it returns the left side if it's falsy, otherwise the right side.
The catch: 0 is falsy, so the expression returns 0, and React renders numbers as text.
What React skips: false, null and undefined render nothing.
Fix: make the left side a real boolean, cartCount > 0 &&, or use a ternary.
“In JavaScript, && doesn't return true or false. It returns the left side if the left side is falsy, and the right side otherwise. When the cart is empty, cartCount is 0, which is falsy, so the whole expression gives back 0. React skips false, null and undefined, but it happily renders a number, so a 0 shows up on the page. The fix is to make sure the left side is a real boolean. I'd write cartCount greater than 0 && the badge, or use a ternary that returns null when there's nothing to show. I've seen the same thing happen with an array's length, so now I always compare explicitly instead of trusting a number to act like false.”
{cartCount > 0 && <Badge count={cartCount} />}
{cartCount > 0 ? <Badge count={cartCount} /> : null}
Guessing that React has a bug, or not knowing that && returns the falsy value itself.
Filter first: keep only the students who passed, before rendering.
Map to JSX: each student becomes an li with a stable key such as the id.
Empty case: check the filtered length and show a message instead.
Keep it simple: compute the list in the component body, not in extra state.
“I'd take the students array as a prop and filter it first, keeping those with marks of 40 or more. I don't store that filtered list in state, because I can work it out from the prop on every render and it's always in sync. Then I check the length. If it's zero, I return a paragraph saying No results, so the user isn't left looking at an empty box. Otherwise I map each student to a list item, showing the name and marks, and give each one the student's id as the key, since ids don't change when the list changes. The whole thing is a few lines, and it's easy to change the pass mark to a prop later if needed.”
function PassedList({ students }) {
const passed = students.filter((s) => s.marks >= 40);
if (passed.length === 0) return <p>No results</p>;
return (
<ul>
{passed.map((s) => (
<li key={s.id}>{s.name}: {s.marks}</li>
))}
</ul>
);
}
Using a for loop that pushes into an array inside JSX, or forgetting the empty case entirely.
New function each render: a component declared inside another is recreated every time the parent renders.
Different type: React sees a new component type, so it removes the old one and mounts a fresh one.
Result: its state is thrown away and the input element is replaced, so focus is lost.
Fix: move the component to the top level and pass what it needs as props.
“Typing updates state in Page, so Page renders again. Because SearchInput is declared inside Page's body, a brand new SearchInput function is created on every render. React decides whether to keep a component by comparing its type with last time, and a new function is a different type, even if the code is identical. So React removes the old SearchInput, with its input element, and mounts a new one. Any state inside it is reset and the input you were typing in is gone, which is why focus drops after each letter. The fix is to move SearchInput out to the top level of the file and pass it the value and the change handler as props. Then it's the same type every render and React just updates it.”
// Outside Page: same component type on every render
function SearchInput({ value, onChange }) {
return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}
function Page() {
const [query, setQuery] = useState('');
return <SearchInput value={query} onChange={setQuery} />;
}
Blaming the browser or adding autofocus to hide it, without seeing that the component is recreated each render.
The mistake: the setter is called while rendering, not on click.
The loop: setting state triggers a render, which calls the setter again, until React stops it.
Fix: pass a function, onClick={() => setCount(count + 1)}.
Arguments: wrap in an arrow function, onClick={() => removeItem(item.id)}.
“onClick needs a function that React will call later, when the button is clicked. With the parentheses there, I'm not passing a function, I'm calling setCount right now, during rendering. Setting state asks React to render again, and that render calls setCount again, so it loops until React stops it with the too many re-renders error. The fix is to wrap it in an arrow function, so onClick gets a function and the setter only runs on a click. The same idea applies when a handler needs an argument, like deleting a specific item. I write an arrow function that calls removeItem with the item's id. If a handler needs no arguments, I can just pass its name, handleClick, without the parentheses.”
<button onClick={() => setCount(count + 1)}>Add</button>
<button onClick={handleReset}>Reset</button>
<button onClick={() => removeItem(item.id)}>Delete</button>
Not being able to explain why the parentheses matter, or fixing it by trial and error without knowing why.
One-way flow: props go down; a child can't change its parent's state directly.
Callback prop: the parent passes a function, often named like onSelect.
Child calls it: on a click, the child calls the function with the data.
Parent decides: the parent updates its own state, and new props flow back down.
“Props only go down, so a child can't reach up and change its parent's state. Instead, the parent passes the child a function as a prop, usually named with on in front, like onSelect. When the user clicks an item, the child calls onSelect and passes the item. The function was written in the parent, so it can call the parent's own state setter. The parent updates its state, renders again, and passes the new selected item back down as a prop. I like this because the child stays simple and reusable. It doesn't know what the parent does with the click. One page might open a detail panel with it, another might add it to a cart, and the list component doesn't change at all.”
function FruitList({ items, onSelect }) {
return items.map((f) => (
<button key={f} onClick={() => onSelect(f)}>{f}</button>
));
}
function Shop() {
const [picked, setPicked] = useState(null);
return (
<>
<FruitList items={['Apple', 'Mango']} onSelect={setPicked} />
<p>You picked: {picked ?? 'nothing yet'}</p>
</>
);
}
Suggesting the child should change the parent's props or reach into the parent's state directly.
children: whatever is placed between the opening and closing tags arrives as props.children.
Render it: put {children} where the content should appear.
Defaults: give optional props a default in the destructuring, like title = 'Details'.
Why: the Card handles the look; the page decides what goes inside.
“Anything I put between a component's opening and closing tags is passed to it as a special prop called children. So in Card I destructure title and children from props, draw a div with the card class for the border, show the title in a heading, and then render children below it. That content could be a paragraph, a form, even another component, and Card doesn't need to know which. For the title, I'd give a default right in the destructuring, say Details, so the card still looks right if someone forgets to pass one. This is how most layout pieces in a real app work, like modals, panels and page sections: the wrapper owns the look and the page fills in what goes inside.”
function Card({ title = 'Details', children }) {
return (
<div className="card">
<h3>{title}</h3>
{children}
</div>
);
}
<Card title="Profile">
<p>Name: Sam</p>
<button>Edit</button>
</Card>
Adding a separate prop for every possible piece of content instead of using children.
State: one number with useState(0).
Updates: use the updater form, setCount((c) => c + 1), so each change starts from the latest value.
The rule: clamp with Math.max(0, c - 1).
User hint: disable the minus button at zero so the rule is obvious.
“I'd keep the count in state starting at zero. For plus and minus I use the updater form of the setter, passing a function that gets the current count, so every change starts from the latest value. For minus, I return the larger of zero and count minus one, so it can never go negative even if someone clicks fast. Reset just sets it back to zero. I'd also disable the minus button when the count is already zero, because that tells the user why nothing happens, rather than a button that silently does nothing. If they wanted a maximum as well, I'd take the min and max as props so the same counter works for things like a quantity picker in a cart.”
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount((c) => Math.max(0, c - 1))} disabled={count === 0}>-</button>
<span>{count}</span>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
Changing a normal variable instead of state and wondering why the screen doesn't update.
Snapshot: name is a constant for this render; the setter doesn't change it.
What the setter does: asks React to render again with the new value.
Where to see it: the next render has the new name.
If you need it now: keep the new value in a local variable and use that.
“State in React works like a snapshot. When the component renders, name is just a constant for that render. Calling setName doesn't change that constant. It tells React to render the component again, and in that next render useState will hand back Maya. My click handler is still running inside the old render, so on the next line name is still the old value. That's expected, not a bug. If I need the new value right away, say to send it to an API in the same handler, I put it in a local variable first, pass that to the setter and use the same variable for the API call. If I just want to see it change, I log it in the component body or check it in the React dev tools.”
function handleSave() {
const nextName = 'Maya';
setName(nextName);
saveProfile({ name: nextName }); // not name, which is still the old value
}
Saying setState is 'slow' or trying to fix it with a delay, instead of explaining the render snapshot.
Copy, don't edit: build a new object with the spread operator, then change one key.
Why: React compares the old and new object; changing the same object in place won't trigger an update.
One handler: give each input a name and use it as a computed key.
Shallow copy: nested objects need their own spread too.
“I don't change the object in state directly. I make a new object by spreading the old one and then overwrite the one field. The setter replaces the whole value, so if I passed only the email, name and city would disappear. So the new object has to carry the other fields along. To avoid three nearly identical handlers, I give each input a name attribute that matches the key, like email. In one handleChange I read the name and value from the event and use square brackets to set that key. I use the updater form so it always starts from the latest form. One thing to watch: spread only copies one level, so if the form had a nested address object, I'd spread that too.”
const [form, setForm] = useState({ name: '', email: '', city: '' });
function handleChange(e) {
const { name, value } = e.target;
setForm((prev) => ({ ...prev, [name]: value }));
}
<input name="email" value={form.email} onChange={handleChange} />
Writing form.email = value and then calling the setter with the same object.
Duplicate data: fullName is just firstName plus lastName.
Risk: one missed update and the three values disagree on screen.
Fix: compute it in the component body on each render.
Rule: state holds only what can't be worked out from other state or props.
“fullName isn't new information. It's just firstName and lastName joined with a space. Keeping it as its own state means every handler has to remember to update it, and the first time someone forgets, say in a new reset button, the screen shows a full name that doesn't match the two fields. It's also extra code for nothing. I'd delete that state and work it out in the component body: a normal constant that joins the two names. It's recalculated on every render, which costs almost nothing, and it can never be out of date. The rule I follow is that state should hold only what I can't work out from other state or props. Filtered lists, totals and counts can usually be worked out the same way.”
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = (firstName + ' ' + lastName).trim();
Adding an effect that copies firstName and lastName into fullName, which is the same duplicate state with an extra render.
State: an array of { id, text, done } and a string for the input.
Add: stop the form reload, ignore empty text, spread the old array plus a new item with a unique id.
Toggle: map to a new array, copying only the item that changed.
Delete: filter out the item by id; use the id as the key.
“I keep two pieces of state: the tasks array, where each task has an id, the text and a done flag, and the text in the input. Adding happens in the form's submit handler. I call preventDefault so the page doesn't reload, skip empty text, then set the array to a new one: the old tasks spread in, plus a new task with a unique id, and clear the input. For toggling, I map over the tasks and, for the matching id, return a copy with done flipped; every other task comes back unchanged. Deleting is a filter that keeps everything except that id. I never push into or edit the existing array, because React only notices a new array. The id also serves as the key, so ticking and deleting never mix up rows.”
function TodoApp() {
const [todos, setTodos] = useState([]);
const [text, setText] = useState('');
function addTodo(e) {
e.preventDefault();
if (!text.trim()) return;
setTodos((prev) => [...prev, { id: crypto.randomUUID(), text: text.trim(), done: false }]);
setText('');
}
const toggle = (id) => setTodos((prev) => prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t)));
const remove = (id) => setTodos((prev) => prev.filter((t) => t.id !== id));
return (
<form onSubmit={addTodo}>
<input value={text} onChange={(e) => setText(e.target.value)} /> <button>Add</button>
<ul>{todos.map((t) => (
<li key={t.id}>
<input type="checkbox" checked={t.done} onChange={() => toggle(t.id)} />
{t.text} <button type="button" onClick={() => remove(t.id)}>Delete</button>
</li>
))}</ul>
</form>
);
}
Pushing into the state array or using the array index as the id, so ticking or deleting affects the wrong task.
Submit on the form: use onSubmit so pressing Enter works too.
Stop the reload: call e.preventDefault() first.
Check and message: validate each field, keep one error message in state, show it near the button.
Real check: the server must validate again; the browser check is only for convenience.
“I put the handler on the form's onSubmit, not on the button's click, so pressing Enter in a field also submits. The first thing the handler does is call preventDefault, because a normal HTML form reloads the page and I'd lose everything. The email and password are kept in state and bound to the inputs. Then I check the fields: if the email has no at sign I set an error message, if the password is shorter than eight characters I set a different one, and I stop there. If both pass, I clear the error and call the login function. The error shows in a paragraph with role alert, so screen readers announce it. And I'd mention that these checks are only for a nicer experience; the server has to check everything again.”
function LoginForm({ onLogin }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
function handleSubmit(e) {
e.preventDefault();
if (!email.includes('@')) return setError('Please enter a valid email.');
if (password.length < 8) return setError('Password needs at least 8 characters.');
setError('');
onLogin({ email, password });
}
return (
<form onSubmit={handleSubmit}>
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
{error && <p role="alert">{error}</p>}
<button type="submit">Log in</button>
</form>
);
}
Forgetting preventDefault, or treating front-end validation as the security check.
Three states: the data, a loading flag and an error.
Fetch once on mount: useEffect with an empty array, calling an async function defined inside it.
Check the response: fetch doesn't reject on a 404 or 500, so check res.ok and throw.
Always finish: turn loading off in finally, then render one of the three states.
“I keep three pieces of state: users starting as an empty array, loading starting as true, and error starting as null. In a useEffect with an empty dependency array, I define an async function and call it, because the effect function itself can't be async. Inside, I await fetch, and then I check res.ok. That's the part people miss: fetch only rejects on a network failure, so a 404 or a 500 comes back as a normal response and I have to throw an error myself. If that passes, I parse the JSON into users. A catch stores the error message, and finally sets loading to false either way. In the JSX I return Loading while loading, the error if there is one, and otherwise the list.”
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function load() {
try {
const res = await fetch('/api/users');
if (!res.ok) throw new Error('Request failed: ' + res.status);
setUsers(await res.json());
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
load();
}, []);
if (loading) return <p>Loading...</p>;
if (error) return <p role="alert">{error}</p>;
return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
Not checking res.ok, so a server error shows up as a crash or an empty list instead of a message.
First render: it happens before the fetch finishes, so the state is still its starting value.
Cause: useState() with no value gives undefined, and undefined has no map.
Also check: the response shape; the list may sit under a key like data.items.
Fix: start with an empty array, or show a loading state until the data is there.
“The API working isn't enough, because the component renders once before the fetch finishes. On that first render the state is still whatever I gave useState at the start. If I wrote useState with nothing in it, the value is undefined, and calling map on undefined crashes. The fix is to start with an empty array, so the first render just maps over nothing, or to show a loading message until the data arrives. The second thing I'd check is the shape of the response. Often the API returns an object with the list inside it, like a data or items key, and I've stored the whole object and then tried to map over that. Logging the parsed response once, or looking in the Network tab, shows it straight away.”
const [products, setProducts] = useState([]); // not useState()
// if the API returns { items: [...] }
const body = await res.json();
setProducts(body.items);
Blaming the API, or wrapping everything in try/catch without understanding the first render.
What and why: one line on what the app did and who used it.
Structure: the main components and why you split them that way.
State: which component owned which data, and one thing that was hard.
Looking back: one honest change you'd make now.
“In my final year, three of us built a room-booking app for our college labs, and I did most of the React side. I split it into a page for each lab, a WeekGrid showing the time slots, a Slot component for each cell and a BookingForm in a modal. At first I kept the bookings inside each Slot, which went wrong fast, because booking one slot didn't update the others or the counts at the top. So I moved the bookings up to the lab page and passed each Slot its data and an onBook function. That was the moment lifting state really made sense to me. Looking back, I'd add loading and error messages from day one, because on the demo day the college Wi-Fi was slow and the page just looked empty.”
Describing only what the app does, with no idea how it was structured or which parts were their own work.
How you split: by page or feature, and who owned what.
Agreements: shared components, props names, folder structure.
Git habits: branches, pull requests, pulling often.
What went wrong: one real conflict and what you changed after it.
“For our semester project, a small events site, there were four of us. We split it by page, so I owned the event list and the event detail page, and one friend owned the sign-up flow. What saved us was agreeing early on a few shared pieces: one Button and one Card component in a common folder, and the shape of an event object, so we weren't guessing at prop names. Each of us worked on a branch and opened a pull request that someone else had to look at before merging. We still had one bad moment when two of us changed the shared Card at the same time and broke each other's pages. After that we agreed that changes to shared components needed a quick message in our group chat first.”
Saying everything went perfectly, or that they just sent each other zip files and copied code over.
Run it first: get the app running locally and find the page in the browser.
Find the code: search for text on that page, or use the React dev tools to find the component.
Copy the pattern: look for an existing button or similar feature and follow how it's done.
Ask smartly: try for a set time, then ask a specific question; keep the first pull request small.
“First I'd get the app running on my machine and open the page in the browser, so I know exactly what I'm changing. To find the code, I'd search the project for a heading or label that's visible on that page, or use the React dev tools to click on the area and see the component's name. Before writing anything, I'd look for a button the codebase already uses and any similar feature, like an existing download, and follow the same patterns, so my change looks like the rest of the code. I'd give myself a fixed amount of time to work things out, and if I'm stuck I'd ask my mentor a specific question, like where the page's data comes from, not a vague 'how does this work'. Then I'd keep the first pull request small.”
Rewriting the page in their own style, or staying stuck for days without asking anyone.
ClapAssist is an AI interview assistant for Mac and Windows. It listens to the interview on your computer and shows you what to say, in short lines you can read while you talk. Your live interview audio and screen are never stored. Your resume and notes are saved to your account so the app fills them in on any computer. It stays out of screen share on every plan, including Free; only you can see it.