PRE SCREENING Q A - rs-hash/Senior GitHub Wiki
- Lifecycle methods are available only in class components and can be used to manage state in various stages of the component's lifecycle.
- Each component has several lifecycle methods such as componentDidMount, componentDidUpdate, componentWillUnmount.
- The following are in the class components
- constructor() - called when the component instance is created
- render() - generates virtual DOM based on props & state
- getDerivedStateFromProps() - during mounting phase it is called after constructor() and before render()(static method )
- componentDidMount() - called when the component is mounted
- shouldComponentUpdate() - called before a component is updated
- componentWillUpdate() - called before the components update cycle is started
- componentDidUpdate() - called after a component has been updated and rerendered
- getSnapshotBeforeUpdate() - called just before the UI is updated
- componentWillUnMount() - called just before the component is removed from the DOM
-
React hooks added to React in the 16.8 version. It allows to manage the state and side effects in functional components. Hooks allow us to write functional React components and still be able to hook into all of the React component functionality, including lifecycle methods.
-
Hooks can be only called in React functional components and cannot be conditional and must be called at the top level of a function component or another custom hook.
-
But the new "use" hook (React 19 canary) can be called within loops and conditional statements like if. Various types of hooks are present like
-
State Hooks - useState, useReducer
-
Context Hooks - useContext
-
Ref Hooks - useRef
-
Effect Hooks - useEffect
-
Performance Hooks - useMemo, useCallback, useTransition, useDeferredValue
-
Resource Hooks - use
-
Others - useId, useDebugValue
class ClassComponent extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
console.log("Component mounted");
}
componentDidUpdate(prevProps, prevState) {
console.log("Component updated");
}
componentWillUnmount() {
console.log("Component will unmount");
}
render() {
return <div></div>;
}
}
export default ClassComponent;import React, { useState, useEffect } from 'react';
const FunctionalComponent = () => {
const [state, setState] = useState(0);
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component will unmount');
};
}, []);
useEffect(() => {
console.log('Component updated');
}, [state]);
return (
<div></div>
);
};
export default FunctionalComponent;- Lifecycle methods provide a granular control over behavior of the component in each lifecycle stages
- Hooks are more flexible and easy way to manage state and side effects in functional components
- Lifecycle methods explicitly define behavior for each lifecycle stage / hooks are modular, easy, reusable
- I personally prefer Hooks over class components since it's simple, cleaner and performant when compared to class components.
2. How do you decide when to use a state management tool (e.g., Redux) in your app? When using one, is there any data you store in other places, and why?
To decide if we need a state management tool for a specific application, we may need to consider various factors which include
- Do we need to cache state from a server and are we using GraphQL or another library to cache?
- Do other parts of the application require data ?
- Is the same data being used in multiple components?
- Do we need time travel debugging ?
- Do we need to store the data consistently when components state update?
- So we have to decide based on the answers if we need Redux / not
- If the application's state is complex and if it's needed across the app and or if the logic is complex to maintain,if we need to cache the data we use a state management tool like Redux. It's best to use if the application requires scalability and maintainability.
- However, if the data is not required to share across the application and is specific to a component and if we already have GraphQL / React Query for caching, in those cases we can use local state / useContext + useReducer .
- useReducer plus useContext together can make up a simple state management system
- Promises in JavaScript are objects used to represent the eventual completion or failure of an asynchronous operation and its resulting value.
- They allow us to write asynchronous code in a more readable and manageable way, especially when dealing with multiple asynchronous tasks or chaining asynchronous operations.
- A promise can be in one of three states: Pending, Fulfilled (Resolved), Rejected.
- To handle multiple promises we can use Promise.all(), Promise.allSettled(), Promise.race(), Promise.any()
- To make an asynchronous task behave synchronously in JavaScript, you can use async/await syntax. This allows you to write asynchronous code in a more synchronous-looking manner.
function fetchData(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = {
// some data
}
if (data) {
resolve(data);
} else {
reject(new Error('not found'));
}
}, 1000);
});
}
const id = 1;
fetchUserData(id)
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error.message);
});async function getData(Id) {
try {
const data = await fetchData(id);
} catch (error) {
console.error('Error fetching data:', error.message);
}
}- It is syntactic sugar on top of promises. In async/await, the async keyword is used to declare an asynchronous function. The await keyword is used to wait for a promise to be resolved. The await keyword can only be used inside an async function.
- The only difference between promise and async/await is the execution context. The code after the Promise creation continues to execute synchronously. Code that follows the creation of promise will execute before the promise callback is executed.
- But await keyword causes the javascript engine to pause the execution of the async function until the promise is resolved/rejected, it does not block the Call Stack.
4. What are factors to consider with front-end app performance? What type of tools can you use to measure performance? Give an example of a performance optimization you have made (or could have made) in the past.
- Initial Assessment and Benchmarking: Conduct an initial assessment of the application's current performance using tools like Lighthouse, PageSpeed Insights, or WebPageTest, Crux. Benchmark key performance metrics such as Load Time, Time to Interactive, First Contentful Paint, and overall page size.
- We can consider bundle size reduction, use lazy loading, optimize images & assets, server side rendering, reduce 3rd party scripts, use CDN & caching tools.
- Tools to use such as Lighthouse, Performance Insights, (Chrome Dev Tools performance profiling), WebPageTest, Webpack Bundle Analyzer, Real User Monitoring (RUM), PageSpeed Insights, CrUX dashboard.
- Improve Core Web Vitals includes LCP, INP, CLS which measures loading, interactivity, and stability of the page.
- Use responsive images, compress if possible, use WebP, image cdn, to improve CLS add width and height to image, reserve space for banners & dynamic content, use aspect-ratio for images, use low resolution placeholder images till it loads.
- Optimize bundle, such as minification, compression, and tree shaking to reduce file sizes and improve load times.
- Remove unused CSS and JS - render blocking resources
- Optimize the critical rendering path by minimizing render-blocking resources, leveraging browser caching, inlining critical CSS and deferring non-critical CSS and JavaScript to prioritize above-the-fold content and reduce render-blocking.
- Virtualize large lists
- Use Performance hooks in React and Server Side Rendering (Next.js)
- Preload critical resources (e.g., above-the-fold content, essential scripts) and prefetch related resources.
- Using content delivery networks (CDNs), can cache resources on behalf of clients. These caches are closer to the user's location, reducing server load.
- Server-Side Cache: Web servers can cache dynamic content or API responses to serve subsequent requests more quickly.
- Example - I used lazy loading to load the content below-the-fold, reduced image size, and used the above tools to improve 12% of the loading time in application in Siemens.
- When I was a fresher I developed a MEAN stack App to monitor the IBM Watson API's status - similar to Grafana but a simple dashboard to monitor the health and status of the backend services.
- Also, I used memoization logic in our codebase which is particularly useful in financial applications where we have financial calculators and for the cases where the inputs don't change frequently.
- Created a style theme design system in Siemens that includes color palette, typography, spacing guidelines, button styles and other UI styles which are used in IPORT App, used SCSS for its ability to use variables, mixins, and nesting. Defined SCSS variables for colors, typography, spacing, breakpoints, and other elements. These variables ensure consistency and flexibility within the Application.