React 技巧和模式

2025-05-25

React 技巧和模式

如果你懂 JavaScript,学习 React 相当容易。然而,在项目规模扩大、重构或重写的过程中,很容易迷失方向,甚至把事情搞砸。我会分享一些技巧,这些技巧真的救了我一命……也节省了我不少时间😇。让我们开始吧!

提示 1:(使用容器)

组件很容易因为代码过多而变得臃肿:API 调用、表单逻辑等等。更糟糕的是,UI 代码也被塞进了这些已经臃肿的组件中。该如何解决这个问题?容器化!容器允许我们将逻辑和 UI 代码隔离到不同的组件中,这有助于我们避免像 MVC 那样导致特定组件臃肿。我们来看一个例子:

该组件获取新闻项目并显示获取的新项目的 UI

const Dashboard = () => {
  const [news, newsError] = useCustomFetch("/news");
  const [user, userError] = useCustomFetch("/user");
  const [trends, trendsError] = useCustomFetch("/trends");
  const [notifications] = useCustomFetch("/notifications");

  if (news) {
    // sort news for tags
    // sort news for "sort options"
    // perform some custom operations on news
    // do something else like caching?
  }

  if (trends) {
    // sort trends for tags
    // sort trends for "sort options"
    // perform some custom operations on trends
    // do something else like caching?
  }

  if (notifications) {
    // sort notifications for tags
    // sort notifications for "sort options"
    // perform some custom operations on notifications
    // do something else like caching?
  }

  return (
    <div>
      <h2>user</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>notifications</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>Latest News</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>Trends</h2>
      loading handler
      map cards
      display available tags
      display sort options
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

我们在这里跳过了大量的逻辑和 UI 代码,但你几乎可以想象,如果任其自行增长,我们的组件会变得多么庞大。现在,让我们看看这个容器化后的示例。

DashboardContainer我们可以将整个代码拆分为和,而不是仅仅包含 Dashboard Dashboard。容器的命名并非强制要求使用 Container ,但这是一个很好的命名约定,就像 MVC 中的控制器一样,例如:UsersController

DashboardContainer.jsx

const DashboardContainer = () => {
  const [news, newsError] = useCustomFetch("/news");
  const [user, userError] = useCustomFetch("/user");
  const [trends, trendsError] = useCustomFetch("/trends");
  const [notifications] = useCustomFetch("/notifications");

  if (news) {
    // sort news for tags
    // sort news for "sort options"
    // perform some custom operations on news
    // do something else like caching?
  }

  if (trends) {
    // sort trends for tags
    // sort trends for "sort options"
    // perform some custom operations on trends
    // do something else like caching?
  }

  if (notifications) {
    // sort notifications for tags
    // sort notifications for "sort options"
    // perform some custom operations on notifications
    // do something else like caching?
  }

  return (
    <Dashboard
      notifications={notifications}
      trends={trends}
      news={news}
      user={user}
      {/* all your other props */}
    />
  );
};
Enter fullscreen mode Exit fullscreen mode

现在,您的仪表板组件将如下所示:

const Dashboard = ({ user, notifications, ... }) => {
  return (
    <div>
      <h2>user</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>notifications</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>Latest News</h2>
      loading handler
      map cards
      display available tags
      display sort options

      <h2>Trends</h2>
      loading handler
      map cards
      display available tags
      display sort options
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

这样,您可以将所有逻辑放在一个组件中,并通过 props 传递 UI 中所需的所有数据。

提示2:(整洁男人的道具😂)

我给这个技巧起了这么一个滑稽的名字,其实是因为我当时在尝试美化代码、精简代码行数时发现了这一点。这里面具体都包含些什么呢?我们来看一下。在上面这个技巧中,我们像这样传递 props:

<Dashboard
  notifications={notifications}
  trends={trends}
  news={news}
  user={user}
/>
Enter fullscreen mode Exit fullscreen mode

这很好,但有时你只需要一些更直接、更容易理解的内容。我们可以用下面的代码替换上面的代码:

const props = { notifications, trends, news, user };

<Dashboard {...props} />
Enter fullscreen mode Exit fullscreen mode

干净、简单、易读😊

提示 3:(错误边界)

根据React 文档,错误边界是指 React 组件,它能够捕获子组件树中任意位置的 JavaScript 错误,记录这些错误,并显示回退 UI 来替代崩溃的组件树。错误边界会在渲染过程中、生命周期方法中以及其下方整个组件树的构造函数中捕获错误。

基本上,应用程序的一部分崩溃不会拖累整个应用程序,而且最重要的是,您可以显示自定义的回退 UI 并记录/报告与应用程序崩溃相关的错误。您只需创建错误边界并将组件作为 props 传递即可。我通常用错误边界包裹整个应用程序。

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

并包装您想要“保护”的组件

<ErrorBoundary>
  <App />
</ErrorBoundary>
Enter fullscreen mode Exit fullscreen mode

就这样。你可以在这里查看文档演示

提示 4:(选择你的库)

不管你喜不喜欢,库决定了你如何编写和组织代码。你可能有某种方法可以做某事,但库最终会决定它接受什么输入以及如何工作。

我在使用 React 时一直遇到的一个问题是,其他库通常不适合你的 React 应用程序,需要大量的样板代码,或者它们只是有一些奇怪的操作😓 顺便说一下,R​​edux 满足所有这些标准😓

不过也有一些好消息,只要你仔细寻找,通常总能找到更简单/更精简的选择。例如,大多数项目并不需要 Redux 的所有功能,只需要一个全局状态、或许还需要 Reducer、一个 Setter 和一个 Getter 即可😅 你可以尝试 Zustand、Reactn 和多功能 React Query 等库。

如果您想要更简单的路由体验,您还可以尝试Glass Router,它对整个路由业务采取更友好的方式。

请记住,社区总是有更简单、更小、通常更快的替代方案。

提示 5:(相对导入)

这适用于 CRA 用户

我们通常将资源、视图以及应用中的所有内容放在不同的目录中。这通常会导致使用 导入时出现问题../../..。有很多解决方案,但最常用的(也是我更喜欢的)方法是重新配置 webpack 以使用相对路径:../../assets我们可以这样:@/assets

设置

我们基本上想先编辑一下 CRA 设置,而无需eject事先进行修改。有一些很好的库可以实现这一点,我们将在项目中安装它们:

yarn add react-app-rewired customize-cra
Enter fullscreen mode Exit fullscreen mode

从那里,我们创建一个config-overrides.js文件并将此代码转储到:

const { override, addWebpackAlias } = require("customize-cra");
const path = require("path");

module.exports = override(
    addWebpackAlias({
        ["@"]: path.resolve(__dirname, "src"),
    })
);
Enter fullscreen mode Exit fullscreen mode

从那里,我们转到package.json脚本部分并替换react-scripts如下react-app-rewired内容:

"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",
  "eject": "react-scripts eject"
}
Enter fullscreen mode Exit fullscreen mode

对于 CRA + JS 用户来说就是这样!

如果您使用带有 CRA 的 TypeScript,则需要添加以下内容,以便编译器不会因为您在导入中使用 @ 而向您大喊大叫。

在您的项目根目录中创建一个新文件tsconfig.base.json(与您的 package.json 在同一级别)并添加以下内容:

{
    "compilerOptions": {
        "paths": {
            "@/*": [
                "src/*"
            ]
        }
    },
}
Enter fullscreen mode Exit fullscreen mode

我们不会在主文件中添加它,tsconfig.json因为 TypeScript 会重写tsconfig.json并抛出这个错误:

The following changes are being made to your tsconfig.json file:
  - compilerOptions.paths must not be set (aliased imports are not supported)
Enter fullscreen mode Exit fullscreen mode

现在要让它工作,您只需要在主tsconfig.json文件中扩展它:

{
  "extends": "./tsconfig.base.json",
Enter fullscreen mode Exit fullscreen mode

您可能需要重启编辑器才能生效(仅限 TypeScript 用户)。之后,您就可以开始替换所有不方便的导入了😇

感谢阅读

这些技巧和窍门帮助我加快了工作流程,保持代码整洁,基本上帮助我克服了懒惰。

如果你有什么想分享的,比如新的技巧、更快的实现我提到的某个功能的方法,或者有什么你不认同的地方,欢迎随时联系我。谢谢!

文章来源:https://dev.to/mychi_darko/react-tips-patterns-4pn3
PREV
通过构建这些出色的应用程序成为一名全栈开发人员
NEXT
使用 React 函数组件保护路由