useCloudStorage
提供 Telegram 云存储功能的 Hook,实现跨设备数据同步,类似于 useState 但数据会持久化并在用户的所有设备间同步。
导入
typescript
import { useCloudStorage, useCloudStorageKeys } from '@xcloud/ui-telegram';示例
API
useCloudStorage
typescript
const [value, setValue, { loading, error, remove, isAvailable }] = useCloudStorage<T>(key, defaultValue);参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| key | string | 是 | 存储的键名 |
| defaultValue | T | 否 | 默认值 |
返回值
一个包含三个元素的数组:
| 索引 | 类型 | 描述 |
|---|---|---|
| 0 | T | undefined | 当前值 |
| 1 | (value: T) => Promise<void> | 更新值的函数 |
| 2 | StorageOptions | 选项对象 |
StorageOptions
| 属性 | 类型 | 描述 |
|---|---|---|
| loading | boolean | 是否正在加载 |
| error | Error | null | 错误信息 |
| remove | () => Promise<void> | 删除值的函数 |
| isAvailable | boolean | 云存储是否可用 |
useCloudStorageKeys
typescript
const { keys, loading, error, refresh, isAvailable } = useCloudStorageKeys();返回值
| 属性 | 类型 | 描述 |
|---|---|---|
| keys | string[] | 所有存储的键名 |
| loading | boolean | 是否正在加载 |
| error | Error | null | 错误信息 |
| refresh | () => Promise<void> | 刷新键列表 |
| isAvailable | boolean | 云存储是否可用 |
使用示例
基础用法 - 字符串存储
存储和获取字符串值:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function ThemeSettings() {
const [theme, setTheme, { loading }] = useCloudStorage('theme', 'light');
if (loading) return <div>Loading...</div>;
return (
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
);
}存储数字
存储计数器或其他数字值:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function Counter() {
const [count, setCount] = useCloudStorage<number>('counter', 0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
<button onClick={() => setCount(count - 1)}>-1</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}存储对象
存储复杂的对象数据:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
interface UserPreferences {
language: string;
notifications: boolean;
theme: 'light' | 'dark';
}
function Preferences() {
const [prefs, setPrefs] = useCloudStorage<UserPreferences>('preferences', {
language: 'en',
notifications: true,
theme: 'light',
});
const updateLanguage = (lang: string) => {
setPrefs({ ...prefs, language: lang });
};
const toggleNotifications = () => {
setPrefs({ ...prefs, notifications: !prefs.notifications });
};
return (
<div>
<select value={prefs.language} onChange={(e) => updateLanguage(e.target.value)}>
<option value="en">English</option>
<option value="zh">中文</option>
</select>
<label>
<input
type="checkbox"
checked={prefs.notifications}
onChange={toggleNotifications}
/>
Enable Notifications
</label>
</div>
);
}存储数组
存储列表数据:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function TodoList() {
const [todos, setTodos] = useCloudStorage<string[]>('todos', []);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, input.trim()]);
setInput('');
}
};
const removeTodo = (index: number) => {
setTodos(todos.filter((_, i) => i !== index));
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => removeTodo(index)}>Remove</button>
</li>
))}
</ul>
</div>
);
}删除数据
删除云存储中的数据:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function UserData() {
const [user, setUser, { remove }] = useCloudStorage('user', null);
const handleLogout = async () => {
await remove(); // 删除用户数据
// 跳转到登录页
};
return (
<div>
{user && (
<div>
<p>Welcome, {user.name}!</p>
<button onClick={handleLogout}>Logout</button>
</div>
)}
</div>
);
}错误处理
处理存储错误:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function Settings() {
const [settings, setSettings, { loading, error }] = useCloudStorage('settings', {});
const handleUpdate = async (newSettings) => {
try {
await setSettings(newSettings);
} catch (err) {
console.error('Failed to save settings:', err);
alert('Failed to save settings');
}
};
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>...</div>;
}检查可用性
在不支持的环境中降级处理:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
function App() {
const [data, setData, { isAvailable }] = useCloudStorage('data', null);
if (!isAvailable) {
// 降级到 localStorage
const fallbackData = localStorage.getItem('data');
return <div>Using fallback storage</div>;
}
return <div>Using cloud storage</div>;
}获取所有键名
查看云存储中的所有键:
tsx
import { useCloudStorageKeys } from '@xcloud/ui-telegram';
function StorageManager() {
const { keys, loading, refresh } = useCloudStorageKeys();
if (loading) return <div>Loading...</div>;
return (
<div>
<h3>Stored Keys ({keys.length}):</h3>
<ul>
{keys.map((key) => (
<li key={key}>{key}</li>
))}
</ul>
<button onClick={refresh}>Refresh</button>
</div>
);
}游戏进度保存
保存游戏进度并跨设备同步:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
interface GameProgress {
level: number;
score: number;
unlockedItems: string[];
}
function Game() {
const [progress, setProgress] = useCloudStorage<GameProgress>('game_progress', {
level: 1,
score: 0,
unlockedItems: [],
});
const levelUp = () => {
setProgress({
...progress,
level: progress.level + 1,
});
};
const addScore = (points: number) => {
setProgress({
...progress,
score: progress.score + points,
});
};
return (
<div>
<p>Level: {progress.level}</p>
<p>Score: {progress.score}</p>
<button onClick={levelUp}>Level Up</button>
<button onClick={() => addScore(100)}>+100 Score</button>
</div>
);
}表单草稿自动保存
自动保存表单内容:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
import { useEffect, useState } from 'react';
function ArticleEditor() {
const [draft, setDraft] = useCloudStorage('article_draft', {
title: '',
content: '',
});
const [localDraft, setLocalDraft] = useState(draft);
// 自动保存 - 防抖
useEffect(() => {
const timer = setTimeout(() => {
setDraft(localDraft);
}, 1000); // 1秒后保存
return () => clearTimeout(timer);
}, [localDraft, setDraft]);
return (
<div>
<input
value={localDraft.title}
onChange={(e) =>
setLocalDraft({ ...localDraft, title: e.target.value })
}
placeholder="Title"
/>
<textarea
value={localDraft.content}
onChange={(e) =>
setLocalDraft({ ...localDraft, content: e.target.value })
}
placeholder="Content"
/>
</div>
);
}多语言设置
存储用户语言偏好:
tsx
import { useCloudStorage } from '@xcloud/ui-telegram';
import { useEffect } from 'react';
import i18n from 'i18next';
function LanguageSelector() {
const [language, setLanguage] = useCloudStorage('language', 'en');
useEffect(() => {
if (language) {
i18n.changeLanguage(language);
}
}, [language]);
return (
<select value={language} onChange={(e) => setLanguage(e.target.value)}>
<option value="en">English</option>
<option value="zh">中文</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
);
}最佳实践
1. 使用 TypeScript 类型
为存储的数据定义明确的类型:
tsx
interface Settings {
theme: 'light' | 'dark';
fontSize: number;
notifications: boolean;
}
const [settings, setSettings] = useCloudStorage<Settings>('settings', {
theme: 'light',
fontSize: 14,
notifications: true,
});2. 提供默认值
始终提供合理的默认值:
tsx
// ✅ 好的做法
const [theme, setTheme] = useCloudStorage('theme', 'light');
// ❌ 不好的做法
const [theme, setTheme] = useCloudStorage('theme'); // 可能为 undefined3. 处理加载状态
在数据加载完成前显示加载指示器:
tsx
const [data, setData, { loading }] = useCloudStorage('data', null);
if (loading) {
return <LoadingSpinner />;
}
return <DataDisplay data={data} />;4. 避免存储大量数据
每个键最多只能存储 4KB 数据:
tsx
// ✅ 好的做法
const [settings, setSettings] = useCloudStorage('settings', {});
// ❌ 不好的做法 - 可能超过 4KB
const [entireDatabase, setEntireDatabase] = useCloudStorage('database', {
users: [...],
posts: [...],
comments: [...],
});5. 使用有意义的键名
使用清晰的键名方便调试和维护:
tsx
// ✅ 好的做法
const [theme, setTheme] = useCloudStorage('user_preferences_theme', 'light');
const [lang, setLang] = useCloudStorage('user_preferences_language', 'en');
// ❌ 不好的做法
const [theme, setTheme] = useCloudStorage('t', 'light');
const [lang, setLang] = useCloudStorage('l', 'en');6. 防抖频繁更新
避免在短时间内频繁写入:
tsx
// 使用防抖
const [value, setValue] = useState('');
const [cloudValue, setCloudValue] = useCloudStorage('value', '');
useEffect(() => {
const timer = setTimeout(() => {
setCloudValue(value);
}, 500);
return () => clearTimeout(timer);
}, [value]);存储限制
- 键数量: 最多 1024 个键
- 键长度: 每个键名最多 128 字节
- 值大小: 每个值最多 4096 字节 (4KB)
- 总大小: 所有键值对总共最多 4MB
数据同步
- 数据会自动在用户的所有设备间同步
- 同步通常在几秒内完成
- 离线时的更改会在重新联网后同步
- 同一键在不同设备上的并发更改,最后的写入会胜出
注意事项
- 云存储仅在 Telegram 环境中可用
- 数据与 Telegram 账号关联,不同用户数据隔离
- 不要存储敏感信息(如密码、令牌等)
- 数据会被序列化为 JSON,不支持函数、Symbol 等特殊类型
- 使用
isAvailable检查功能可用性,在不支持的环境中提供降级方案
相关 API
- useInitData - 获取 Telegram 初始化数据
- useAuth - 认证功能