chevron-left chevron-right

What to answer when questions about React appear at job interview?

If you want to become a React developer then it's likely you'll meet the situation that you will get asked about React and what are the crucial features of that library. In this text I'm going to give some sample questions regarding interviews for a React developer position and I'll list crucial features of React that came with 16.x branch of it.

What features appeared in React 16.x?

In this section you'll get an overview of what kind features appeared in specific React 16.x versions. The list contains only the crucial features, that changed the daily work of most React developers.

React supports browsers from IE11 and newer only (v.16.0.0)

Since this version React supports browsers from IE11 and newer, because this library is using Map and Set collection types in the codebase, as well as requestAnimationFrame by default. If you want to support older browsers versions then you should include polyfills in your app.

Error boundaries (v.16.0.0)

One of the most useful features coming with React 16.x series. In the past debugging error stack trace in React was cumbersome, not mentioning unexpected UI crashes. Having implemented this feature helps us to handle such situations by providing a fallback UI in case of any errors. The app won't be broken anymore and an app users will be happy and they will be able to keep using it without a need of reloading app.

Let's have a look at a sample implementation of error boundary feature in React:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }
 
  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, errorInfo);
  }
 
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
 
    return this.props.children; 
  }
}

I've used the code sample from the docs page to describe how it works.

First of all, you have to create a component that handles 2 methods:

  • getDerivedStateFromError - a static method that allows to update our state in case of any error;
  • componentDidCatch - a method that intercepts any error that appeared in any of component's children. In this method you can do any additional actions like logging to any kind of services, like Google Analytics or anything else.

It's important to note, that this component catches errors not related to:

  • event handlers,
  • async code (like timeouts or requestAnimationFrame),
  • server side rendering,
  • the error boundary component itself. It catches errors in its children, not inside itself.

Another important thing to mention is that the error boundary component has to be a class component. Currently, it's not possible to catch errors with hooks.

React Portal (v.16.1.0)

I bet you've implemented modals many times (if you ever built any application). It's always tricky to implement such, because of element positioning and index issues in CSS. Badly implemented modals or backdrops (semi-transparent background layer around modal) can be frustrating.

In React, components are responsible for its own DOM. Rendering some parts of DOM outside of React component container leaded to many unexpected issues. But since the React Portal API introduction the issues are gone. React library can now control a specific DOM node from outside of component's scope.

Here you can find a code sample used to render a React children component outside of React parent component:

1
2
3
4
<body>
    <div id="app-container"></div>
    <div id="modal-container"></div>
</body>

And some JS:

1
2
3
4
5
6
7
const domNode = document.querySelector('#modal-container');
const child = <SomeComponent />;
 
ReactDOM.createPortal(
    child,
    domNode
);

And that's it! Pretty simple and very useful. React can now control parts of a component outside of React component's scope.

React Fragment (v.16.2.0)

Another cool feature that came with React 16.x series is Fragment API. Browsers support native document.createDocumentFragment() function that creates a virtual container for DOM nodes. It's not assigned to any HTML tag. It can be used to render multiple DOM elements performantly inside any loop. You can add auto-generated DOM nodes to the fragment and then append the fragment directly to real DOM structure.

The advantage of this solution compared to creation of

element with document.createElement('div'); is quite obvious (at least to me). You don't have to create any additional DOM nodes that contains children DOM nodes inside. It gives more flexibility in terms of DOM manipulations and layout styling.

The same is with React Fragment API. It does the same in terms of grouping components without a need of introduction of another

container.

1
2
3
4
5
6
7
8
9
const Component = () => {
    return (
        <React.Fragment>
            <ComponentA />
            <ComponentB />
            <ComponentC />
        </React.Fragment>
    )
};

Alternatively, you can use the following syntax:

1
2
3
4
5
6
7
8
9
const Component = () => {
    return (
        <>
            <ComponentA />
            <ComponentB />
            <ComponentC />
        </>
    )
};

I prefer the latter one.

React Context API (v.16.3.0)

This feature is one of the most important ones. It solves the problem of passing data down from the parent component to the bottom level child component. Drilling down props is one of the biggest challenges in regular React development. Basically, it means that you have to pass some values from a parent component to deeply nested component, while the values are not used by any components in between them.

You would have to define props validation for each component or just pass the props without a validation (risky!), without thinking about what kind of props is really needed.

Let's take a look at the example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const NestedChild = ({ importantProp }) => <h3>{importantProp}</h3>;
const Child = ({ importantProp }) => {
    return (
        <div>
            <h2>Child</h2>
            <NestedChild importantProp={importantProp}/>
        </div>
    );
}
const Parent = ({ importantProp }) => {
    return (
        <div>
            <h1>Parent</h1>
            <Child importantProp={importantProp} />
        </div>
    )
}

In the sample above you can see a classic case of props drilling. The importanProp is not used by both Parent and Child components, but it's used only by NestedChild component.

When there's not so many props drilling down, then we can live with it, but when there's much more of them, then it becomes difficult to maintain in the long term.

The React Context API is coming to the rescue in such situations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const initialValue = 'some-important-prop'
const ImportPropContext = React.createContext(initialValue);
 
class MyComponent extends React.Component {
    constructor(props) {
        super(props);
 
        this.state = {
            importantProp: initialValue
        }
    }
 
    render() {
        return (
            <ImportantPropContext.Provider value={this.state.importantProp}>
                <Parent />
            </ImportantPropContext.Provider>
        );
    }
}
 
const NestedChild = () => {
    return (
        <ImportantPropContext.Consumer>
            {(importantProp) => <h3>{importantProp}</h3>}
        </ImportantPropContext.Consumer>
    )
}

As you can see, there's no need to define importantProp prop in intermediate components. We've defined a context in the topmost component, passed the value through the context provider and consumed with the context consumer.

One thing different here is that in the NestedChild component, in order to consume a value, you have to pass a function as a children. Then, inside the function you can get the value and render it.

With hooks it will get even simpler (in React 16.8).

React.lazy() (v.16.6.0)

Developing apps in React is not very complicated task and it's relatively easy to add new features to an existing codebase. But when the codebase grows, the app weight grows as well. Oftentimes you don't need all the app features loaded at the same time. This is the place where the code-splitting comes to the rescue.

With React, since version 16.6.x, you can tell React and bundlers which components are lazily loaded and can be loaded on demand. That version introduced React.lazy() function converts a function rendering a component to a JS Promise, that will be resolved when needed.

The React.lazy() function has to be used along with Suspense React component, that knows how to handle lazy-loaded components. See the example:

1
2
3
4
5
6
7
8
const Child = React.lazy(() => import('./Child'));
const Parent = () => {
    return (
        <React.Suspense fallback={<div>Loading Child component ...</div>}>
            <Child />
        </React.Suspense> 
    )
};

The React.Suspense component takes one prop: fallback. This prop accepts any React element as a value and it's used to display a fallback view while loading children component.

This feature can be extremely useful while loading heavy features on demand. With small components the difference will be unnoticed.

React hooks (v.16.8.0)

This is a real game changer in React development. I still remember the first time when I heard about it. At first it was a strange concept, that I started to like. IMO, it is easier to develop new features with it now.

The concepts of handling state in React apps by using hooks was englightening. For the simple state management you can omit using Redux and start using hooks like React.useState, React.useReducer and React.useContext. With these 3 hooks you can simulate Redux in simpler use cases.

The list of hooks coming out of the box with React 16.8.x is as follows:

  • useState - for handling state management for a single property,
  • useReducer - for handling action-like state management,
  • useContext - for dealing with contexts in the codebase,
  • useEffect - a kind of replacement for componentDidMount, componentDidUpdate, componentWillUnmount,
  • useRef - allows to deal with keeping references to variables that would be overwritten by component re-renders,
  • useCallback - makes a reference to instance of component's inner function,
  • useMemo - especially useful when component's inner function has to make a lot of heavy calculations. Stores the output of calculations.
  • useLayoutEffect,
  • useDebugValue,
  • useImperativeHandle

The last three hooks have never been used by myself in web app development. I suggest reading about them in the hooks docs.

Another cool fact is you can develop own hooks that fulfil project needs.

React developer position sample questions

In this section I will provide some sample questions that might appear during any job interviews for a React developer position. Answers to these questions will be provided as well.

What is JSX?

JSX is a shorthand for JavaScript XML. This syntax allows using HTML markup and JS code next to each other. It's a React approach for templating components.

How to manage state in React apps?

There are many ways of managing component state in React. Some of them were already mentioned earlier, like:

  • using specific hooks for state management,
  • using specifc hooks for working with context,
  • using Redux or any other library that allows to work with state in a specific way.

It's worth to mention, that state is responsible for dealing with internal component state. Cannot be directly affected from outside of component.

What's the difference between state and props?

Props are variables injected to a component from another component that wraps it. Props look like HTML attributes, but they allow to pass a reference to any kind of values. While native HTML attributes cannot pass information from complicated types like functions or objects (unless it's stringified). You can control a child component by changing props values passed to a child component.

Meanwhile, state is internally scoped to a component. State variables cannot leak outside of a component, unless a component author decides so. It can be updated by props changes if desired.

Summary

I hope that after reading this article you'll get some basic knowledge regarding React features (or at least it's a refreshment of you already know). I wrote this article because during the recruitment processes I've been involved as a recruiter (building my frontend team) many people say that the only feature that came with React 16.x are hooks. I wanted to list some of the most useful features available in React. Because React 16.x is not only about hooks (while they're stars obviously).

At the end of the article, I decided to list some questions and answers to them. These questions often appear at screenings and first phases of technical interviews. It's good to know the answers.

If you have any comments, please do not hesitate to put them under this article.