# 最近使用的颜色

> 用 recentColors 和 onRecentColorsChange 持久保存 React 颜色选择器的最近使用色块，页面刷新后列表依然保留，不会被清空。

Source: https://chroma-panel.jscrate.dev/zh/react/recipes/recent-colors
Last updated: 2026-09-21

选择器的底栏中有一行最近使用过的颜色，默认情况下，每次挂载时这一行都是空的。如果用户会经常回到同一个选择器，比如画布编辑器或后台的主题设置页，重新找到昨天用过的颜色往往最费时间，这时就值得把它保存下来。这个列表只是一个普通的字符串数组，存在哪里由你决定。

```tsx
"use client";

import { ColorInput } from "chroma-panel";
import "chroma-panel/style.css";
import { useEffect, useState } from "react";

const STORAGE_KEY = "chroma-panel:recent";

export function BrandColorInput() {
  const [recent, setRecent] = useState<string[]>([]);

  useEffect(() => {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (raw === null) return;
    try {
      const parsed: unknown = JSON.parse(raw);
      if (Array.isArray(parsed)) {
        setRecent(parsed.filter((c): c is string => typeof c === "string"));
      }
    } catch {
      window.localStorage.removeItem(STORAGE_KEY);
    }
  }, []);

  return (
    <ColorInput
      name="brand"
      defaultValue="#3366cc"
      recentColors={recent}
      onRecentColorsChange={(colors) => {
        setRecent(colors);
        window.localStorage.setItem(STORAGE_KEY, JSON.stringify(colors));
      }}
    />
  );
}
```

读取操作放在 effect 中，而不是渲染过程中，这样服务端渲染和客户端首次渲染得到的都是空列表，不会出现不一致。通用规则请参阅[服务端渲染](https://chroma-panel.jscrate.dev/zh/react/handbook/server-rendering)。

## 哪些颜色会进入列表

面板添加颜色的时机和 `onChangeComplete` 触发的时机相同：在修改提交时，而不是拖动过程中。颜色以六位十六进制字符串的形式加入，所以即使开启了 `showAlpha`，历史记录中也不包含透明度。

添加之前，列表会按颜色而不是按字符串去重，所以 `#3366CC` 和 `#3366cc` 算作同一项，然后最多保留十个。`onRecentColorsChange` 每次交给你的都是处理完毕的列表，所以上面的回调可以直接把参数原样存起来。

> **可能少显示一个色块**
>
> 底栏会隐藏与当前选中颜色相同的那个最近使用色块，因为点击它不会有任何效果。存储的列表仍然是完整的，只是这一行看起来少了一个。

## 受控还是非受控

`recentColors` 和 `defaultRecentColors` 的用法与 `value` 和 `defaultValue` 相同，详见[受控与非受控](https://chroma-panel.jscrate.dev/zh/react/handbook/controlled)。

传入 `defaultRecentColors` 可以设置列表的初始值，之后交给面板自己管理。它只在面板挂载时读取一次，所以在 effect 中从存储里读出的列表对它来说已经太晚了。这正是 `recentColors` 的用途，也是开头示例使用它的原因。

```tsx
<ColorInput defaultRecentColors={["#3366cc", "#cc3366"]} />
```

传入 `recentColors` 后，面板就不再保存自己的副本。它会用新列表应有的内容调用 `onRecentColorsChange`，然后渲染你传回的列表。所以如果忘了保存结果，这一行就会一直不变。

## 自己添加颜色

如果你在面板之外还有自己的色块按钮，可以用 `pushRecent`，它和面板遵循同样的规则，两条路径得到的是同一份一致的历史记录。

```tsx
import { pushRecent } from "chroma-panel";

setRecent((current) => pushRecent(current, "#cc3366"));
```

它的签名是 `pushRecent(list, hex, limit?)`，`limit` 默认为十。它返回一个新数组，不会修改你传入的数组。

## 关闭这一行

`showRecentColors={false}` 会把它去掉。一次性的选择器没有值得保留的历史，就可以这样做。这一行本身以及它旁边的取色器，详见 [PanelFooter 参考文档](https://chroma-panel.jscrate.dev/zh/react/components/panel-footer)。
