Câu hỏi Reactjs Hay
Câu hỏi Reactjs Hay
1️⃣ React Rendering Behavior
A. “Why does a component re-render?”
Short spoken answer:
“In React, a component re-renders whenever its inputs change: props, state, or any context it consumes. It can also re-render if its parent re-renders and React decides this subtree might need updating.”
Deeper points you can add:
A function component will re-run when:
-
Its state changes (
setState/setXfromuseState,useReducer). -
Its props change (from the parent’s render).
-
Context values it uses change (
useContext). -
Key changes (React treats it as a new component).
-
External subscriptions (e.g. Redux, Zustand) indicate a change and cause a re-render of that connected component.
Important nuance:
“React always re-runs the render function when these inputs change, but that doesn’t mean the DOM always changes afterward. Reconciliation determines what actually updates in the DOM.”
B. “How does React decide when to skip rendering?”
Careful: two things here – re-running the component vs updating the DOM.
1. Skipping DOM updates (reconciliation):
“After rendering to virtual DOM, React diffs the new tree with the previous one. If an element has the same type and key and its props are shallow-equal, React reuses the existing DOM node and only updates what actually changed.”
Key rules:
-
Same element type + same key → React does a shallow prop diff and only updates changed props.
-
Different type or key → React throws away that subtree and recreates it.
2. Skipping the render call for a component:
“At the component level, React can skip calling the function entirely if I use optimizations like
React.memo,PureComponent, or customshouldComponentUpdate. They all rely on shallow comparison of props (and sometimes state).”
So you can say:
“By default, React will re-run the component whenever the parent re-renders, but it will try to minimize actual DOM changes via the diffing algorithm. If I want to avoid the render call itself, I use tools like
React.memoand make sure my props are referentially stable.”
C. “React.memo, useMemo, useCallback — when (and when NOT) to use them?”
1. React.memo
How to explain:
“
React.memois a higher-order component that memoizes the result of a component’s render. If the props are shallow-equal between renders, React skips calling that component.”
Use when:
-
The component:
-
Is pure (render output depends only on props).
-
Is re-rendering often due to parent updates.
-
Has non-trivial work inside (heavy tree, expensive calculations).
-
Avoid / be careful when:
-
Props are almost always changing → shallow compare cost + no benefit.
-
You pass new inline objects/arrays/functions all the time → memo is useless unless you also stabilize those references (
useCallback,useMemo). -
For very small, cheap components – extra comparison overhead can be worse than the re-render.
2. useMemo
How to explain:
“
useMemomemoizes a value. I use it for expensive calculations or to keep referential equality for derived data.”
Use when:
-
You have expensive computation that would otherwise run on every render.
-
You need stable references for:
-
Derived arrays / objects used as props for memoized children.
-
Dependencies in
useEffectoruseCallback.
-
Avoid when:
-
The computation is cheap →
useMemoadds overhead and complexity. -
You use it everywhere “just in case” → this is a common anti-pattern.
You can say:
“I use
useMemoas a targeted optimization after I observe a real performance issue, not as default boilerplate.”
3. useCallback
How to explain:
“
useCallbackmemoizes a function reference. It’s useful when passing callbacks to memoized children, or as stable dependencies for hooks likeuseEffect.”
Use when:
-
You pass a callback to a child wrapped with
React.memo,memoizedlist items, etc. -
A hook depends on a function (e.g.
useEffect,useEventListener), and you need a stable reference to avoid re-running the effect unnecessarily.
Avoid when:
-
The function is not passed down or used in dependencies → no benefit.
-
You’re wrapping every handler by default → mental and performance overhead.
Nice one-liner:
“
React.memoskips component renders,useMemomemoizes values, anduseCallbackmemoizes functions. I only use them where they reduce real work, not as decoration.”
2️⃣ How the Browser Works
A. “Critical Rendering Path – what is it?”
Good spoken answer:
“The Critical Rendering Path is the sequence the browser follows to turn HTML, CSS, and JS into pixels on the screen. Minimizing work on this path improves load performance and perceived speed.”
Steps you can list:
-
Download & parse HTML → DOM
-
Download & parse CSS → CSSOM
-
Combine DOM + CSSOM → Render Tree
-
Layout (calculate positions & sizes)
-
Paint (draw pixels for each node)
-
Composite (merge layers into the final image on screen)
Quick extra:
“Blocking CSS or synchronous JS can delay this pipeline, so in practice I care about reducing critical CSS, deferring non-critical scripts, and avoiding render-blocking resources.”
B. “Layout → Paint → Composite — what happens here?”
You can say:
“Once the browser has the render tree, it goes through three main steps per frame:
Layout – compute geometry: positions, sizes, box model.
Paint – draw text, borders, backgrounds, shadows for each element onto layers.
Composite – the GPU or compositor combines layers and applies transforms to produce the final frame.”
Why it matters for you as a front-end dev:
-
Layout is expensive, especially when it cascades through big parts of the tree.
-
Paint is also relatively heavy (especially shadows, gradients, complex borders).
-
Compositing is cheaper, usually GPU-accelerated and isolated to layers.
C. “What triggers reflow (layout)?”
Reflow = layout. It happens when the browser needs to recalculate element geometry.
Examples that trigger reflow:
-
Changing layout-related styles:
-
width,height,margin,padding,border,position,display,font-size, etc.
-
-
Manipulating the DOM structure:
-
Adding/removing nodes, changing content, changing classes that affect layout.
-
-
Reading layout properties after writes (layout thrashing):
-
Accessing
offsetHeight,getBoundingClientRect(),scrollHeight, etc., after changing styles → forces sync layout to give you the correct value.
-
Nice explanation:
“When I change something that affects box geometry, or I force the browser to measure layout right after a change, I trigger a reflow. On large pages or inside animations, that’s expensive, so I batch DOM writes and read layout carefully.”
D. “Why are transform + opacity preferred for animations?”
This is a classic performance question.
Answer like this:
“Animating
transformandopacityis preferred because they can usually be done purely in the compositing step, without triggering layout or paint.”
Details you can mention:
-
Properties like
top,left,width,height,margin:-
Affect layout → reflow + repaint + composite on every frame.
-
-
Properties like
background-color,box-shadow:-
Don’t change layout but do require repaint + composite.
-
-
transformandopacity(when the element is on its own layer):-
Can be updated by the compositor only, often via GPU.
-
No layout, no paint → smoother 60fps animations on lower-end devices.
-
So you can sum up:
“For performant animations I stick to
transform(e.g. translate, scale) andopacity, let the browser promote that element to a layer, and avoid touching layout-affecting properties inside animations.”
====
ChatGPT said: