使用React Content Font提高字体加载效率
Published: 2023-07-19 15:31:23

Language:
- [English](https://dev.to/adbutterfield/making-font-loading-more-efficient-with-react-content-font-4bbd)
- [日本語](https://dev.to/adbutterfield/react-content-fontdehuontonodu-miip-miwoxiao-lu-hua-suru-20oo)
- [中文](https://dev.to/adbutterfield/shi-yong-react-content-fontti-gao-zi-ti-jia-zai-xiao-lu-3ink)

在网络性能方面，每个千字节都至关重要。开发者不断努力使应用程序更高效，无论用户的网络速度如何，都能确保顺畅的用户体验。这在开发日语或中文等拥有大量字符集的应用程序时尤为重要。在这些情况下，如何有效使用字体可能会成为主要的关注点，因为字体的大小通常非常大。

其中一个挑战是处理像日语这样需要大字体文件的语言。例如，单一的Noto Sans日语字体重量达到惊人的5.7 MB。让用户下载这样大的文件并不理想，更不用说如果你需要更多的字体重量。

[React Content Font](https://www.npmjs.com/package/react-content-font)，一种专门为解决这个问题而开发的包，就此登场。

## 什么是React Content Font?

[React Content Font](https://www.npmjs.com/package/react-content-font)是一个为React应用程序设计的包。它通过检查网页，获取页面上的独特字符列表，然后请求Google Fonts中仅包含这些字符的字体。这个过程使用了优化的请求，确保只加载所需的字符，最大限度地减少了用户需要下载的数据。

使用此包非常简便，只需在应用程序的高层添加上下文提供者即可。简单地提供你想要的字体的fontName属性，它将默认请求一个普通的（即400）重量的字体。

例如，如果你有一个使用 App Router 的 Next.js应用，你可以像这样更新你的 `app/layout.tsx`文件：
```tsx
import FontProvider from 'react-content-font';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="jp">
      <body>
        <FontProvider fontName="Noto Sans JP">{children}</FontProvider>
      </body>
    </html>
  );
}
```
如果你需要多于一个字体重量，甚至是一些重量的斜体版本，[React Content Font](https://www.npmjs.com/package/react-content-font)通过`fontWeights`属性为你提供了支持。
```tsx
import FontProvider from 'react-content-font';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="jp">
      <body>
        <FontProvider fontName="Noto Sans JP" fontWeights={[400, 600]}>
          {children}
        </FontProvider>
      </body>
    </html>
  );
}
```
## 满足多样的字体需求

你可能会想知道是否有任何日语字体带有斜体变体。虽然这不常见，但也许你想使用的字体确实具有这个特性。[React Content Font](https://www.npmjs.com/package/react-content-font)允许你请求你想要的任何重量的斜体变体。
```tsx
import FontProvider from 'react-content-font';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="jp">
      <body>
        <FontProvider
          fontName="Noto Sans JP"
          fontWeights={[400, 600, ['ital', 400], ['ital', 900]]}
        >
          {children}
        </FontProvider>
      </body>
    </html>
  );
}
```
此外，该包还允许你指定`font-display`属性。这个属性定义了字体文件如何被浏览器加载和渲染，这直接影响到性能的感知。
```tsx
import FontProvider from 'react-content-font';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="jp">
      <body>
        <FontProvider fontName="Noto Sans JP" display="block">
          {children}
        </FontProvider>
      </body>
    </html>
  );
}
```
## 检查字体加载状态

在某些情况下，你可能希望在显示内容之前等待字体加载，或者显示一个加载状态。[React Content Font](https://www.npmjs.com/package/react-content-font)提供了一个可以标记字体加载状态的hook。这个特性允许你根据字体的加载状态控制内容的可见性。
```tsx
'use client';

import { useFontContext } from 'react-content-font';

export default function PageText() {
  const { isFontLoaded } = useFontContext();

  return (
    <p style={{ visibility: isFontLoaded ? 'visible' : 'hidden' }}>
      よそはほかまあこの威圧心というのの後をしないう。きっと場合で仕事帰りはひょろひょろその評でたなりでするが行くたをも表裏できなけれでば、なぜにはもっなないうた。個人にできたのはついに十月から向後ますだない。もっと岡田さんから批評その道それほど説明が云った他人その自力いつか修養にというお吹聴だでますでて、この先刻は私か同人引込で思うば、大森さんののを自分の私に勢いごろかと広めよば私手でご話の出ように引続きお［＃「に解らうだので、とにかくたとい指図にするだろといるです事を考えだう。
    </p>
  );
}
```
然而，关键的是要渲染文本，这样字符才能被发现并包含在请求的字体中。

## 检测字体更新

[React Content Font](https://www.npmjs.com/package/react-content-font)也允许你知道字体是否正在更新，为你的应用程序的用户体验提供了另一层控制。
```tsx
'use client';

import { useFontContext } from 'react-content-font';

export default function PageText() {
  const { isFontLoaded } = useFontContext();

  return (
    <>
      {isFontLoaded && (
        <p>
          よそはほかまあこの威圧心というのの後をしないう。きっと場合で仕事帰りはひょろひょろその評でたなりでするが行くたをも表裏できなけれでば、なぜにはもっなないうた。個人にできたのはついに十月から向後ますだない。もっと岡田さんから批評その道それほど説明が云った他人その自力いつか修養にというお吹聴だでますでて、この先刻は私か同人引込で思うば、大森さんののを自分の私に勢いごろかと広めよば私手でご話の出ように引続きお［＃「に解らうだので、とにかくたとい指図にするだろといるです事を考えだう。
        </p>
      )}
    </>
  )
}
```
再次强调，就像检查加载状态一样，你必须渲染文本，这样字符才能被发现并包含在请求的字体中。

## 让我知道你的想法！

作为[React Content Font](https://www.npmjs.com/package/react-content-font)背后的唯一开发者，我发现这个旅程充满挑战，但也很有回报。这是我为自己建立的东西，但我很确定其他人也会想要使用它。

你在你的项目中发现这个包有用吗？你是否看到任何可以改进的地方？或者，你有没有一些创新的想法用于未来的增强？我很愿意听到你的想法！