DEV Community

João Guilherme do Amaral Vequiato
João Guilherme do Amaral Vequiato

Posted on

6 React questions for technical interviews and their answers

Throughout my career as a developer I have been able to go through some selection processes, with different difficulties and questions about certain subjects.

I decided to gather in this post the most common questions and their respective answers.

Not for them to be decorated, but because I think they are extremely important to understand for anyone looking to evolve in their career as a React developer.

1. What is the difference between Component and PureComponent?

A component in React is a function or class that returns a React element, which is a description of a user interface.

A pure component is a component that implements the shouldComponentUpdate lifecycle method in a way that prevents the component from re-rendering if the component's props and state have not changed.

Here is an example of a simple component:

function HelloWorld(props) {
  return <div>Hello, {props.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Here is an example of the same component implemented as a pure component:

class HelloWorld extends React.PureComponent {
  render() {
    return <div>Hello, {this.props.name}</div>;
  }
}
Enter fullscreen mode Exit fullscreen mode

The main difference between a component and a pure component is that a pure component implements shouldComponentUpdate with a shallow prop and state comparison, while a component does not.

This means that a pure component will not re-render if its props and state have not changed, while a component will always re-render every time it is rendered.

Using a pure component can improve performance in cases where the component is rendered frequently and the component's props and state do not change often.

However, if the component's props or state do change frequently, using a pure component can prevent the component from updating when it should, which can break the app.

2. Describe 3 ways to pass information from a component to its parent.

There are several ways to pass information from a child component to its parent in React:

Callback functions: You can pass a callback function as a prop to the child component. The child component can then call the callback function when it needs to pass data back to the parent. For example:

// In the parent component:

function Parent() {
  const handleChildData = data => {
    // Do something with the data from the child component
  };

  return <Child onChildData={handleChildData} />;
}

// In the child component:

function Child(props) {
  const handleClick = () => {
    const data = "some data";
    props.onChildData(data);
  };

  return <button onClick={handleClick}>Click me</button>;
}
Enter fullscreen mode Exit fullscreen mode

Context: You can use the React context feature to pass data from a child component to a parent component. The parent component creates a context object and the child component consumes it. For example:

// In the parent component:

const DataContext = React.createContext();

function Parent() {
  const [data, setData] = React.useState(null);

  return (
    <DataContext.Provider value={[data, setData]}>
      <Child />
    </DataContext.Provider>
  );
}

// In the child component:

function Child() {
  const [data, setData] = React.useContext(DataContext);

  const handleClick = () => {
    setData("some data");
  };

  return <button onClick={handleClick}>Click me</button>;
}
Enter fullscreen mode Exit fullscreen mode

Ref: We can pass a ref to the children component, so we can acess the value with ref.current in the parent component:

 const inputReft = useRef();

  <InputComponent ref={inputRef}>
Enter fullscreen mode Exit fullscreen mode

3. Give 2 ways to prevent components from re-rendering.

There are several ways to prevent a component from re-rendering in React:

React.PureComponent: As mentioned previously, you can use React.PureComponent instead of React.

Component when defining a component class.

React.PureComponent implements the shouldComponentUpdate lifecycle method with a shallow prop and state comparison, which means that the component will only re-render if its props or state have changed.

If the props and state are the same according to the comparison, the component will not re-render.

class MyComponent extends React.PureComponent {
  render() {
    // Render the component
  }
}
Enter fullscreen mode Exit fullscreen mode

React.memo: You can use the React.memo higher-order component to wrap a function component and prevent it from re-rendering if its props have not changed.

React.memo performs a shallow comparison of the props to determine if the component should re-render.

If the props are the same according to the comparison, the component will not re-render.

const MyComponent = React.memo(function MyComponent(props) {
  // Render the component
});
Enter fullscreen mode Exit fullscreen mode

You can also provide a custom comparison function to React.memo if you need to perform a more complex comparison of the props. For example:

const areEqual = (prevProps, nextProps) => {
  // Return true if the props are equal, false otherwise
};

const MyComponent = React.memo(function MyComponent(props) {
  // Render the component
}, areEqual);
Enter fullscreen mode Exit fullscreen mode

4. How many arguments does setState take and why is it async.

The setState method in React takes up to two arguments.

The first argument is an updater function or an object representing the new state.

The second argument is an optional callback function that is called after the state has been updated.

Here is an example of using setState with an updater function:

this.setState(prevState => {
  return {
    count: prevState.count + 1
  };
});

Enter fullscreen mode Exit fullscreen mode

Here is an example of using setState with an object representing the new state:

this.setState({
  count: this.state.count + 1
});

Enter fullscreen mode Exit fullscreen mode

setState is asynchronous because it may be batched together with other state updates, which means that the state may not be updated immediately after calling setState.

This is done to improve performance by avoiding unnecessary re-renders.

If you need to perform an action after the state has been updated, you can pass a callback function as the second argument to setState. The callback function will be called after the state has been updated and the component has re-rendered.

this.setState(
  {
    count: this.state.count + 1
  },
  () => {
    // Do something after the state has been updated
  }
);
Enter fullscreen mode Exit fullscreen mode

It is important to note that the state may be updated asynchronously, so you should not rely on the state being immediately available after calling setState.

If you need to use the updated state in a subsequent update, you should pass a function as the first argument to setState and use the current state as an argument to the function.

this.setState(prevState => {
  return {
    count: prevState.count + 1
  };
});

// The state may not be immediately available, so it is important to use
// the previous state as an argument to the updater function
this.setState(prevState => {
  return {
    count: prevState.count + 1
  };
});

Enter fullscreen mode Exit fullscreen mode

5. What is a fragment and why do we need it?

In React, a fragment is a way to group a list of children without adding extra nodes to the DOM.

Fragments are useful when you want to return multiple elements from a component's render method, but you don't want to wrap the elements in an extra DOM node.

Here is an example of using a fragment to group a list of elements:

render() {
  return (
    <>
      <p>Item 1</p>
      <p>Item 2</p>
      <p>Item 3</p>
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

This will render the same JSX as the following code:

render() {
  return (
    <React.Fragment>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </React.Fragment>
  );
}

Enter fullscreen mode Exit fullscreen mode

Both of these examples will render a list with three items, but the fragment allows you to group the elements without adding an extra node to the DOM.

This can be useful in cases where you want to return multiple elements from a component, but you don't want to wrap the elements in an extra node.

In the past, you could use a div element as a placeholder for a fragment, but this is no longer recommended because it can lead to confusion and can cause problems with CSS.

It is now recommended to use fragments or a React.Fragment element to group elements in a list.

6. List the steps needed to migrate a Class to Function Component.

To migrate a class component to a function component in React, you can follow these steps:

  1. Convert the class component to a function component. To do this, you will need to remove the class keyword and the extends clause, and add the function keyword. You should also remove the render method and move the JSX code to the top level of the component function.
// Before:
class MyComponent extends React.Component {
  render() {
    return <div>Hello, world!</div>;
  }
}

// After:
function MyComponent(props) {
  return <div>Hello, world!</div>;
}

Enter fullscreen mode Exit fullscreen mode
  1. Convert any instance variables or methods to function component hooks. If the class component uses any instance variables or methods, you will need to convert them to function component hooks. This includes variables like this.state and this.props, as well as methods like this.setState.
// Before:
class MyComponent extends React.Component {
  state = { count: 0 };

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>Click me</button>
        <p>{this.state.count}</p>
      </div>
    );
  }
}

// After:
function MyComponent() {
  const [count, setCount] = React.useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <button onClick={handleClick}>Click me</button>
      <p>{count}</p>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode
  1. Remove the constructor method. If the class component has a constructor method, you can remove it, since function components do not have a constructor method.
// Before:
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // Initialize state and bind methods
  }

  // Other methods and render function
}

// After:
function MyComponent(props) {
  // Initialize state using hooks and define methods as functions
  // Render function
}

Enter fullscreen mode Exit fullscreen mode
  1. Convert any static methods or properties to regular functions or variables. If the class component has any static methods or properties, you will need to convert them to regular functions or variables.
// Before:
class MyComponent extends React.Component {
  static propTypes = {
    name: PropTypes.string.isRequired
  };

  static defaultProps = {
    name: "world"
  };

  // Other methods and render function
}

// After:
MyComponent.propTypes = {
  name: PropTypes.string.isRequired
};

MyComponent.defaultProps = {
  name: "world"
};

function MyComponent(props) {
  // Render function
}

Enter fullscreen mode Exit fullscreen mode

After following these steps, your class component should be fully converted to a function component.

Extra (a Javascript question) - What's the difference in handling exceptions in promises, callbacks and async...await.

In JavaScript, there are three main ways to handle exceptions: using try...catch with synchronous code, using a callback function, and using async/await. Here is a brief overview of the differences between these three approaches:

try...catch: try...catch is used to handle exceptions in synchronous code. When an exception is thrown in the try block, the code execution is immediately halted and the catch block is executed.

try {
  // Code that may throw an exception
} catch (error) {
  // Handle the exception
}
Enter fullscreen mode Exit fullscreen mode

Callbacks: Callbacks are used to handle asynchronous exceptions. When an asynchronous function returns a result or an error, it calls a callback function with the result or the error as an argument. The callback function can then handle the result or the error as needed.

asyncFunction(function(error, result) {
  if (error) {
    // Handle the error
  } else {
    // Use the result
  }
});

Enter fullscreen mode Exit fullscreen mode

async/await: async/await is a more recent approach to handling asynchronous exceptions. async functions allow you to use the await keyword to pause the execution of the function until a promise is resolved. If the promise is rejected, an exception is thrown, which can be handled using a try...catch block.

async function example() {
  try {
    const result = await asyncFunction();
    // Use the result
  } catch (error) {
    // Handle the error
  }
}
Enter fullscreen mode Exit fullscreen mode

In general, try...catch is used to handle exceptions in synchronous code, while call

Top comments (2)

Collapse
 
pcelac profile image
Aleks

That's how interviews were looking like in 2019, when hooks were introduced.

Collapse
 
jgamaraalv profile image
João Guilherme do Amaral Vequiato

Believe it or not, the same questions are still used today