通过像专业人士一样渲染列表在 React 面试中脱颖而出 标准实施改进 结论

2025-05-24

通过像专业人士一样渲染列表在 React 面试中脱颖而出

标准实施

改进

结论

在 React 面试中,我们经常会被要求渲染列表。本文将介绍一个基本的实现,并提出四种改进方法,使其脱颖而出。

标准实施

让我们看一个基于项目数组渲染列表的基本实现。在继续阅读之前,请尝试想出至少三种不同的改进方法。

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;
Enter fullscreen mode Exit fullscreen mode

改进

以下是我们可以做的四项改进,以脱颖而出。在面试过程中,清晰地解释原因至关重要。

1. 指定密钥

通过为列表项组件提供一个keyprop,我们可以帮助 React 在比较原始树和后续树时识别每个项目。需要强调的是,该keyprop 必须是唯一的,并且不应使用索引作为参数key(更改列表上的顺序不会更改项目的标识)。

{posts.map((post) => (
  <Post key={post.id} post={post} onPostClick={onPostClick} />
))}
Enter fullscreen mode Exit fullscreen mode

2. 优化渲染

每次我们点击列表项时,我们都会重新PostList渲染Post

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

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

  return <div onClick={onClick}>{post}</div>;
};
Enter fullscreen mode Exit fullscreen mode

我们可以PostList使用memoReact 提供的功能来优化组件。当我们用 包裹组件时memo,我们告诉 React 除非 props 发生变化,否则不要重新渲染该组件。

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

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

然而,我们会注意到,即使使用了 ,我们的组件仍然会继续重新渲染memoApp每次currentPost状态改变时,我们的组件都会重新渲染。每次重新渲染,它都会重新创建onPostClick函数。当一个函数被重新创建时(即使是相同的实现),它都会拥有一个新的身份。因此,从技术上讲,props 确实发生了变化,这意味着PostList它会重新渲染。

const fn1 = () => {};
const fn2 = () => {};
fn1 === fn2; // => false
Enter fullscreen mode Exit fullscreen mode

我们可以使用钩子告诉 React 不要重新创建该函数useCallback

const onPostClick = useCallback((post) => {
  setCurrentPost(post);
}, []);
Enter fullscreen mode Exit fullscreen mode

在上一个示例中,使用useCallback可能是合理的,因为它阻止了我们重新渲染所有帖子。需要指出的是,将函数包装在 中并不总是合理的useCallback

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

  return <div onClick={onClick}>{post.title}</div>;
};
Enter fullscreen mode Exit fullscreen mode

我们可以向面试官指出,在组件useCallback中使用Post可能没有意义,因为在这种情况下组件是轻量级的。我们只应该useCallback在有意义的情况下使用(我们可以通过性能分析来测试)。 也有一些缺点useCallback;它增加了代码的复杂性,并且调用useCallback会在每次渲染时运行额外的代码。

3. 组件卸载时进行清理

目前,组件卸载时我们不会进行任何清理。例如,如果我们决定在收到 URL 响应之前离开页面,该怎么办?我们应该取消请求。

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

useEffect可以分为两部分:挂载时运行的代码和卸载时运行的代码:

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

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

AbortController我们可以通过使用并调用controller.abort()清理来取消请求。

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();
  };
}, []);
Enter fullscreen mode Exit fullscreen mode

4. 添加辅助功能

最终,真正能区分优秀候选人的测试是候选人能否谈论可访问性。我们的示例应用程序过于简单,无法添加任何实质性的可访问性改进。一旦应用程序变得复杂,我们绝对应该讨论一些需要注意的事项。我们可以运行的一个测试是,我们能否仅使用键盘来使用示例应用程序?一个快速解决方案是将项目转换为按钮,以便我们可以使用键盘进行 Tab 切换。

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

  return <button onClick={onClick}>{post}</button>;
};
Enter fullscreen mode Exit fullscreen mode

结论

在 React 中渲染列表乍一看似乎是一道简单的面试题。有时,求职者可能会感到沮丧,为什么自己明明能够实现一个可行的解决方案却没能通过面试。下次再遇到这个问题,一定要跟面试官沟通(如果有时间的话,最好能实现一下),看看我们能如何像专业人士一样渲染列表。

文章来源:https://dev.to/andyrewlee/stand-out-in-a-react-interview-by-rendering-a-list-like-a-pro-1cn5
PREV
React 面试中的 4 大错误
NEXT
React State 中更新对象和数组的速查表