Importanat Interview questions
- Event Loop In Depth
- UseCallBack
- UseMemo
- React.memo
- useRef
Event Loop
Javascript is an asynchronous , single threaded & non-blocking language.
It is non-blocking
due to the Event Loop.
JS can off-loads tasks like async task to other workers and continue executing without waiting for the result.
Event loop helps by managing this task.
Jargons
- Call Stack : This is where our code is executed.
-
Web APIs : When async op. like
setTimeout fetch
are called, they are handled by Web APIs. -
Queues
- MicroTask Queue : It is a special queue that hold microtasks that are scheduled to run right after the current call stack is empty, but before any macrotasks like
setTimeout,setInterval
.- It contains Promises.then , Promises.finally , Promises.catch.
- MacroTask Queue : It is the queue in which callbacks from the async code are stored that will be executed after the microtask is empty.
- It contains setTimeout , setTimeInterval , fetch , DOM events , file operations, IO operations etc.
- MicroTask Queue : It is a special queue that hold microtasks that are scheduled to run right after the current call stack is empty, but before any macrotasks like
Flow
- The sync. code is executed in the call stack.
- when the stack is empty, execute the task in the
microtask queue
. - Once the
microtask task is empty
, execute a task from themacrotask queue
. - Repeat 2 & 3.
// 1. Call stack + Macrotask queue
console.log("1");
setTimeout(()=>{
console.log("2");
},0)
console.log("3");
// Output : 1 3 2
// 2. call stack + Micro & macro task queue
console.log("1");
setTimeout(()=>{
console.log("2");
},0)
Promise.resolve().then(()=>{
console.log("3");
})
console.log("4");
// Output : 1 4 3 2
// 3. Micro Task creating more microtask
console.log("1");
setTimeout(()=>{
console.log("2");
},0)
Promise.resolve().then(()=>{
console.log("3");
Promise.resolve().then(()=>{
console.log("4");
})
})
console.log("5");
// OUTPUT : 1 ,5,3,4,2
// 4. MIX
console.log("Start");
setTimeout(() => {
console.log("Timeout 1");
}, 0);
Promise.resolve()
.then(() => {
console.log("Promise 1");
setTimeout(() => {
console.log("Timeout 2");
}, 0);
});
setTimeout(() => {
console.log("Timeout 3");
}, 0);
console.log("End");
// OUTPUT
// Start
// End
// Promise 1
// Timeout 1
// Timeout 3
// Timeout 2
useCallBack
It is React Hook
that returns a memoized function.
Memoized Function : A Function that is cached and is not recreated on every render.
The function will only be recreated when the dependencies change.
const handleClick = useCallback(() => {
// do something
}, [dependencies]);
// This function will only be recreated when the dependencies change.
// If the dependencies are empty, the function will never be recreated, unless it is unmount and remounted.
const handleClick = useCallback(() => {
// do something
}, []);
Problem with useCallBack
- It can store the stale data.
const [count, setCount] = useState(0);
// This will store the stale data.
const handleClick = useCallback(() => {
console.log(count);
}, []);
// FIX - 1
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
// FIX - 2
// if we pass the handleClick function to child component, so event time function is recreated the component rerendered to change this we use ref.
const countRef = useRef(count);
useEffect(()=>{
countRef.current = count;
},count)
const handleClick = useCallback(() => {
console.log(count);
}, []);
useMemo
It is a React Hook
that returns a memoized value.
// It returns a memoized value rather than a memozied function.
const memoizedValue = useMemo(() => {
// Expensive computation
return result;
}, [dependencies]);
// Here is a memoized function using useMemo
const handleClick = useMemo(()=>()=>{
setCount(count+1);
},[count])
React.memo
It is a Higher Order Component
that memoizes the component.It prevents the components from rerendering unless the props are changed.
// On Every Render it compares the prv prop values with newer value, It only do shallow comparison.
const MyComponent = React.memo((props) => {
// Component code
});
Problems with React.memo
- if the props are objects , array & function, then if different refernce is passed it will cause rerender.
- It only checks for props, not for state & context.
useRef
It is a React Hook
that returns a mutable ref object that persists across rerenders.
const ref = useRef(0);
// Access it using
console.log(ref.current);
// Modify it using , also updating it doesn't cause re-render.
ref.current = 10;
// We can attach it to DOM element to access them directly.
const inputRef = useRef(null);
// Get value : inputRef.current.value
// Set value : inputRef.current.value = "Hello"
// Focus : inputRef.current.focus()
// Blur : inputRef.current.blur()
<input ref={inputRef} />
It can use to presists values across re-renders. It will useful for timers or intervals, to store timeIDs
const timerRef = useRef();
function startInterval(){
timerRef = setInterval(()=>{
// do something
},[3000])
}
function removeInterval(){
clearInterval(timeRef);
}
# Storing previous State
function prevState(){
const [count,setCount] = useState(0);
const counRef = useRef();
const handleClick = ()=>{
setCount((prev)=>prev+1);
}
// will 1st run after render
useEffect(()=>{
// doesn't cause rerender
countRef.current = count;
},[count])
return <>
<h1>Current State : {count}</h1>
<h1>Previous State : {countRef.current} </h1>
<button onClick={handleClick}>Increment Count</button>
</>
}
// Flow
// Component Mounts
// count = 0 & countRef = undefined [DISPLAYING THIS]
// useEffect Runs
// count = 0 & countRed=f = 0;
// Increment the state
// count = 1
// Rerender happens
// count = 1 & countRef = 0 [DISPLAYING THIS]
// useEffect Runs
// count 1 & counte=Ref = 1
useRef doesn't cause component re-rendering, so if we are using it in a component, its value will not displayed
useEffect
It is a React Hook
that lets you perform side effect in functional components.
side effects
are the operations that effects things outside the scope of the component.
For example:
Fetching data from an API
Updating the DOM manually
Setting a timer
Subscribing to a WebSocket
Listening to window resize events
// Run for first time only
useEffect(()=>{
// do something
},[])
// Runs for first time and after that only when the count changes
useEffect(()=>{
// do something
},[count])
useEffect(()=>{
// runs before component unmount.
return ()=>{
// do something
}
},[])
// Runs on every render
useEffect(()=>{
// do something
})