React Interview Questions

React Interview Questions

Created
Aug 22, 2024 11:35 AM
Tags

Fundamentals

React Application Lifecycle

There are four different phases in the lifecycle of React component. They are:
  • Initialization: During this phase, React component will prepare by setting up the default props and initial state for the upcoming tough journey.
  • Mounting: Mounting refers to putting the elements into the browser DOM. Since React uses VirtualDOM, the entire browser DOM which has been currently rendered would not be refreshed. This phase includes the lifecycle methods componentWillMount and componentDidMount.
  • Updating: In this phase, a component will be updated when there is a change in the state or props of a component. This phase will have lifecycle methods like componentWillUpdateshouldComponentUpdaterender, and componentDidUpdate.
  • Unmounting: In this last phase of the component lifecycle, the component will be removed from the DOM or will be unmounted from the browser DOM. This phase will have the lifecycle method named componentWillUnmount.
notion image

JSX?

JSX stands for JavaScript XML. It allows us to write HTML inside JavaScript and place them in the DOM without using functions like appendChild( ) or createElement( ).
As stated in the official docs of React, JSX provides syntactic sugar for React.createElement( ) function.
Note- We can create react applications without using JSX as well.

Virtual DOM

As stated by the react team, virtual DOM is a concept where a virtual representation of the real DOM is kept inside the memory and is synced with the real DOM by a library such as ReactDOM.
notion image
notion image

React State

Every component in react has a built-in state object, which contains all the property values that belong to that component.In other words, the state object controls the behaviour of a component. Any change in the property values of the state object leads to the re-rendering of the component.
Note- State object is not available in functional components but, we can use React Hooks to add state to a functional component.
How to declare a state object?
Example:
class Car extends React.Component{ constructor(props){ super(props); this.state = { brand: "BMW", color: "black" } } }
How to use and update the state object?
class Car extends React.Component { constructor(props) { super(props); this.state = { brand: "BMW", color: "Black" }; } changeColor() { this.setState(prevState => { return { color: "Red" }; }); } render() { return ( <div> <button onClick={() => this.changeColor()}>Change Color</button> <p>{this.state.color}</p> </div> ); } }

React Props

Every React component accepts a single object argument called props (which stands for “properties”).  These props can be passed to a component using HTML attributes and the component accepts these props as an argument.Using props, we can pass data from one component to another.
While rendering a component, we can pass the props as an HTML attribute:
<Car brand="Mercedes"/>
In Class component:
class Car extends React.Component { constructor(props) { super(props); this.state = { brand: this.props.brand, color: "Black" }; } }
In Functional component:
function Car(props) { let [brand, setBrand] = useState(props.brand); }
Note- Props are read-only. They cannot be manipulated or changed inside a component.

Error boundary

Introduced in version 16 of React, Error boundaries provide a way for us to catch errors that occur in the render phase.
Any component which uses one of the following lifecycle methods is considered an error boundary.
In what places can an error boundary detect an error?
  1. Render phase
  1. Inside a lifecycle method
  1. Inside the constructor
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { logErrorToMyService(error, errorInfo); } render() { if (this.state.hasError) { return <h4>Something went wrong</h4> } return this.props.children; } }
In the code above, getDerivedStateFromError function renders the fallback UI interface when the render method has an error.
componentDidCatch logs the error information to an error tracking service.
Now with the error boundary, we can render the CounterComponent in the following way:
<ErrorBoundary> <CounterComponent/> </ErrorBoundary>

React Hooks

React Hooks are the built-in functions that permit developers for using the state and lifecycle methods within React components. These are newly added features made available in React 16.8 version.
There are 2 rules which must be followed while you code with Hooks:
  • React Hooks must be called only at the top level. It is not allowed to call them inside the nested functions, loops, or conditions.
  • It is allowed to call the Hooks only from the React Function Components.
  1. useState() : Its a built-in React Hook that allows you for having state variables in functional components. It should be used when the DOM has something that is dynamically manipulating/controlling.
    1. ... const [count, setCounter] = useState(0); const [otherStuffs, setOtherStuffs] = useState(...); ... const setCount = () => { setCounter(count + 1); setOtherStuffs(...); ... };
  1. useEffect() : It is used to perform side effects in functional components—operations that occur outside the main rendering process. These side effects can include tasks like fetching data from APIs, directly manipulating the DOM, setting up event listeners or subscriptions, and cleaning up resources when a component unmounts.
      • It runs after the component renders, meaning the DOM is updated before the effect runs.
      • It takes two arguments:
          1. A callback function containing the side effect logic.
          1. An optional dependency array that controls when the effect should re-run.
      useEffect(() => { // Side effect code here return () => { // Optional cleanup code here (e.g., remove event listeners) }; }, [dependencies]);
      • If you provide a dependency array ([dependencies]), React re-runs the effect only when one of those dependencies changes.
      • If the array is empty ([]), the effect runs only once after the initial render (similar to componentDidMount).
      • If no dependency array is provided, the effect runs after every render.
      • The optional return function inside useEffect is a cleanup function, useful for cleaning resources such as timers, subscriptions, or event listeners before the effect re-runs or when the component unmounts.
      • useEffect can have multiple instances in a component, each handling different side effects independently.
      • You should include all variables used inside the useEffect callback that come from the component scope in the dependency array to avoid stale closures and ensure correct behavior.
  1.  useCallback() : It is used to memoize a callback function, meaning it caches the function instance so that the same function reference is returned between component renders unless its dependencies change. This helps prevent unnecessary re-creation of the function on every render, which is beneficial for optimizing performance, especially when passing callbacks to child components or using them as dependencies in other hooks like useEffect.
      • Syntax:
        • const memoizedCallback = useCallback(() => { // Your callback logic here }, [dependencies]);
          It takes two arguments: the callback function to memoize and an array of dependencies. The memoized function only updates if a dependency changes.
      • How it works:
          1. On the initial render, it creates and returns the callback function.
          1. On subsequent renders, if dependencies have not changed, it returns the same function instance from the previous render.
          1. If any dependency changes, a new function instance is created and returned.
      • Why use useCallback:
        • Prevents unnecessary re-renders of child components that rely on function props by stabilizing function references.
        • Improves performance in scenarios such as rendering lists where callbacks are passed repeatedly.
        • Helps avoid unwanted re-execution of effects when functions are dependencies.
        • Useful in preserving function references in custom hooks
  1. useRef() : It is used to persist a mutable value across component renders without causing re-renders when the value changes. It returns a plain JavaScript object with a single property, current, which holds the mutable value.
      • Basic usage: const ref = useRef(initialValue);
        • Here, ref is an object with a .current property initially set to initialValue. This value can be read or mutated directly, and it will persist between renders without triggering re-renders.
      • Common use cases:
          1. Accessing DOM elements: By attaching a ref object to a JSX element via the ref attribute, ref.current will point to the corresponding DOM node after rendering, allowing direct DOM manipulation like focusing an input.
          const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); }, []); return <input ref={inputRef} />;
          1. Storing mutable values that do not trigger re-render: Useful for storing things like timers, previous state values, or any mutable data you want to keep between renders without causing updates.
          const countRef = useRef(0); countRef.current = someNewValue; // Updates without re-rendering
          1. Tracking previous state or props: You can store the previous value for comparison purposes.
        • Characteristics:
          • Changing ref.current does not trigger a component re-render.
          • The ref object itself is stable; the same object is returned on every render.
          • Typically used for imperative DOM manipulation or holding mutable values.
        • When to use useRef rather than useState:
          • Use useRef when you want to persist some value without it causing a UI update. For UI-changing values, useState is preferred
  1. useContext() : It is used for creating common data that is to be accessed by the components hierarchy without having to pass the props down to each level.
  1. useReducer() : It is used when there is a complex state logic that is having several sub-values or when the upcoming state is dependent on the previous state. It will also enable you to optimization of component performance that will trigger deeper updates as it is permitted to pass the dispatch down instead of callbacks.
  1. useMemo() : This will be used for recomputing the memoized value when there is a change in one of the dependencies. This optimization will help for avoiding expensive calculations on each render.
  1. useImperativeHandle(): It will enable modifying the instance that will be passed with the ref object.
  1. useDebugValue(): It is used for displaying a label for custom hooks in React DevTools.
  1. useLayoutEffect(): It is used for the reading layout from the DOM and re-rendering synchronously.

Custom Hooks

A Custom Hook is a function in Javascript whose name begins with ‘use’ and which calls other hooks. It is a part of React v16.8 hook update and permits you for reusing the stateful logic without any need for component hierarchy restructuring.
In almost all of the cases, custom hooks are considered to be sufficient for replacing render props and HoCs (Higher-Order components) and reducing the amount of nesting required. Custom Hooks will allow you for avoiding multiple layers of abstraction or wrapper hell that might come along with Render Props and HoCs.
The disadvantage of Custom Hooks is it cannot be used inside of the classes.

Higher Order Components

Simply put, Higher-Order Component(HOC) is a function that takes in a component and returns a new component.
While developing React applications, we might develop components that are quite similar to each other with minute differences. In most cases, developing similar components might not be an issue but, while developing larger applications we need to keep our code DRY, therefore, we want an abstraction that allows us to define this logic in a single place and share it across components. HOC allows us to create that abstraction.

QnA

What are the differences between controlled and uncontrolled components?

Controlled and uncontrolled components are just different approaches to handling input from elements in react.
Feature
Uncontrolled
Controlled
Name attrs
One-time value retrieval (e.g. on submit)
✔️
✔️
✔️
Validating on submit
✔️
✔️
✔️
Field-level Validation
✔️
✔️
Conditionally disabling submit button
✔️
✔️
Enforcing input format
✔️
✔️
several inputs for one piece of data
✔️
✔️
dynamic inputs
✔️
🤔
  • Controlled component: In a controlled component, the value of the input element is controlled by React. We store the state of the input element inside the code, and by using event-based callbacks, any changes made to the input element will be reflected in the code as well.
function FormValidation(props) { let [inputValue, setInputValue] = useState(""); let updateInput = e => { setInputValue(e.target.value); }; return ( <div> <form> <input type="text" value={inputValue} onChange={updateInput} /> </form> </div> ); }
  • Uncontrolled component: In an uncontrolled component, the value of the input element is handled by the DOM itself. Input elements inside uncontrolled components work just like normal HTML input form elements.The state of the input element is handled by the DOM. Whenever the value of the input element is changed, event-based callbacks are not called. Basically, react does not perform any action when there are changes made to the input element.
function FormValidation(props) { let inputValue = React.createRef(); let handleSubmit = e => { alert(`Input value: ${inputValue.current.value}`); e.preventDefault(); }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" ref={inputValue} /> <button type="submit">Submit</button> </form> </div> ); }

Differentiate React Hooks vs Classes.

React Hooks
Classes
It is used in functional components of React.
It is used in class-based components of React.
It will not require a declaration of any kind of constructor.
It is necessary to declare the constructor inside the class component.
It does not require the use of this keyword in state declaration or modification.
Keyword this will be used in state declaration (this.state) and in modification (this.setState()).
It is easier to use because of the useState functionality.
No specific function is available for helping us to access the state and its corresponding setState variable.
React Hooks can be helpful in implementing Redux and context API.
Because of the long setup of state declarations, class states are generally not preferred.
notion image