Stand out in a React interview by rendering a list like a pro
Tags: react, javascript, webdev, beginners
Published: 2022-11-13 08:18:46

We often get asked to render a list in a React interview. In this article we are going to look at a basic implementation and come up with four ways we can improve it to stand out from the rest.

# Standard Implementation

Let's look at a basic implementation where we render a list based on an array of items. Try to think of at least three different ways we can improve the following implementation before reading further.

```js
import { useState, useEffect } from "react";

const App = () => {
  const [posts, setPosts] = useState([]);
  const [currentPost, setCurrentPost] = useState(undefined);

  useEffect(() => {
    const initialize = async () => {
      const res = await fetch("https://jsonplaceholder.typicode.com/posts");
      const json = await res.json();
      setPosts(json);
    };
    initialize();
  }, []);

  const onPostClick = (post) => {
    setCurrentPost(post);
  };

  return (
    <div>
      {currentPost && <h1>{currentPost.title}</h1>}
      <PostList posts={posts} onPostClick={onPostClick} />
    </div>
  );
};

const PostList = ({ posts, onPostClick }) => {
  return (
    <div>
      {posts.map((post) => (
        <Post post={post} onPostClick={onPostClick} />
      ))}
    </div>
  );
};

const Post = ({ post, onPostClick }) => {
  const onClick = () => {
    onPostClick(post);
  };

  return <div onClick={onClick}>{post.title}</div>;
};

export default App;
```

# Improvements

Here are the four improvements that we can make to stand out. It’s important we articulate the why during the course of the interview.

## 1. Specify Key

By providing a `key` prop to our list item components, we help React identify each item when it compares the original tree with its subsequent tree. It’s important to emphasize that the `key` prop needs to be unique and we shouldn’t use an index as a `key` (changing the order on the list doesn’t change the identity of the item).

```js
{posts.map((post) => (
  <Post key={post.id} post={post} onPostClick={onPostClick} />
))}
```

## 2. Optimize Rendering

Every time we click on a list item, we are re-rendering `PostList` and every `Post`.

```js
const Post = ({ post, onPostClick }) => {
  console.log("post rendered");

  const onClick = () => {
    onPostClick(post);
  };

  return <div onClick={onClick}>{post}</div>;
};
```

We can optimize our `PostList` component by using the `memo` function provided by React. When we wrap our component with `memo`, we are telling React to not re-render this component unless the props have changed.

```js
import { useState, useEffect, memo } from "react";

const PostList = memo(({ posts, onPostClick }) => {
  return (
    <div>
      {posts.map((post) => (
        <Post post={post} onPostClick={onPostClick} />
      ))}
    </div>
  );
});
```

However, we will notice that our component continues to re-render even with `memo`. Our `App` re-renders every time `currentPost` state changes. Every re-render it is re-creating the `onPostClick` function. When a function is re-created (even if it’s the same implementation), it has a new identity. Therefore, the props technically did change, which means `PostList` will re-render.

```js
const fn1 = () => {};
const fn2 = () => {};
fn1 === fn2; // => false
```

We can tell React to not re-create the function by using the `useCallback` hook.

```js
const onPostClick = useCallback((post) => {
  setCurrentPost(post);
}, []);
```

Using `useCallback` might have made sense in the previous example because it is preventing us from re-rendering all of the posts again. It’s important to point out that it doesn’t always make sense to wrap a function in a `useCallback`.

```js
const Post = ({ post, onPostClick }) => {
  const useCalllback(onClick = () => {
    onPostClick(post);
  }, []);

  return <div onClick={onClick}>{post.title}</div>;
};
```

We can point out to the interviewer that using the `useCallback` in the `Post` component might not make sense because the component in this case is lightweight. We should only use `useCallback` if it makes sense (we can test by profiling). There are downsides to `useCallback`; it increases the complexity of the code and calling `useCallback` is additional code that gets run on every render.

## 3. Clean up when component un-mounts

Right now we are not doing any sort of clean up when the component un-mounts. For example, what if we decide to navigate away from the page before we get a response from our URL? We should cancel the request.

```js
useEffect(() => {
  const initialize = async () => {
    const res = await fetch("https://jsonplaceholder.typicode.com/posts");
    const json = await res.json();
    setPosts(json);
  };
  initialize();
}, []);
```

`useEffect` can be split up into two parts: code to run on mount and code to run on unmount:

```js
useEffect(() => {
  // When component mounts what code should I run?

  return () => {
    // When component unmounts what code should I run (clean up)?
  };
}, []);
```

We can cancel the request by using the `AbortController` and calling `controller.abort()` on clean up.

```js
useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  const initialize = async () => {
    try {
      const res = await fetch("https://jsonplaceholder.typicode.com/posts", { signal });
      const json = await res.json();
      setPosts(json);
    } catch (err) {
      console.log(err);
    }
  };

  initialize();

  return () => {
    controller.abort();
  };
}, []);
```

## 4. Add accessibility

Final test that truly separates an exceptional candidate is if the candidate can talk about [accessibility](https://reactjs.org/docs/accessibility.html). Our sample application is too simple to add any tangible accessibility improvements, we should definitely talk about some things to look out for once our application grows in complexity. One test we can run is, can we use our sample application using the keyboard alone? One quick fix would be to convert items into buttons so that we can tab through them using our keyboard.

```js
const Post = ({ post, onPostClick }) => {
  const onClick = () => {
    onPostClick(post);
  };

  return <button onClick={onClick}>{post}</button>;
};
```

# Conclusion

Rendering a list in React seems like a simple interview question at first. Sometimes candidates might get frustrated why they didn’t pass the interview despite being able to implement a working solution. Next time we encounter this question, make sure to communicate to the interviewer (and implement them if given the time) the different ways we can render a list like a pro.