管理面板 API:Redux 存储与 reducers
🌐 Admin Panel API: Redux store & reducers
Page summary:
在
register期间使用addReducers()向 Redux 存储添加自定义状态。然后使用useSelector读取状态,使用useDispatch更新状态,并使用useStore订阅更改。admin_app切片暴露主题、语言环境、权限和认证数据。🌐 Use
addReducers()duringregisterto add custom state to the Redux store. Then read state withuseSelector, update it withuseDispatch, and subscribe to changes withuseStore. Theadmin_appslice exposes theme, locale, permissions, and authentication data.
Strapi 的管理面板使用全局 Redux 存储来管理应用状态。插件可以访问此存储以读取状态、分发动作以及订阅状态变化。这使得插件能够与核心管理功能进行交互,例如主题设置、语言偏好和身份验证状态。
🌐 Strapi's admin panel uses a global Redux store to manage application state. Plugins can access this store to read state, dispatch actions, and subscribe to state changes. This enables plugins to interact with core admin functionality like theme settings, language preferences, and authentication state.
在深入了解本页的概念之前,请确保你已经:
🌐 Before diving deeper into the concepts on this page, please ensure you have:
- 创建了一个 Strapi 插件,
- 已阅读并理解了 管理面板 API 的基础知识
存储概览
🌐 Store overview
Redux 存储通过 React Redux 的 Provider 自动提供给所有插件组件。该存储包含几个切片:
🌐 The Redux store is automatically provided to all plugin components through React Redux's Provider. The store contains several slices:
admin_app:核心管理状态,包括主题、语言、权限和身份验证令牌adminApi:管理员端点的 RTK 查询 API 状态- 插件特定的切片:插件添加的额 外 reducer
添加自定义 reducers
🌐 Adding custom reducers
Reducers 是 Redux 可以用于在组件之间共享状态的 reducers。Reducer 在以下情况下可能有用:
- 应用中的许多地方都需要大量的应用状态。
- 应用状态经常更新。
- 更新该状态的逻辑可能很复杂。
可以在 register 生命周期期间使用 addReducers() 函数将 reducers 添加到插件接口。
🌐 Reducers can be added to a plugin interface with the addReducers() function during the register lifecycle.
使用以下语法将化简器声明为对象:
🌐 A reducer is declared as an object with this syntax:
- JavaScript
- TypeScript
import { exampleReducer } from './reducers'
import pluginId from './pluginId'
const reducers = {
// Reducer Syntax
[`${pluginId}_exampleReducer`]: exampleReducer
}
export default {
register(app) {
app.addReducers(reducers)
},
bootstrap() {},
};
import type { StrapiApp } from '@strapi/admin/strapi-admin';
import { exampleReducer } from './reducers';
import pluginId from './pluginId';
const reducers = {
[`${pluginId}_exampleReducer`]: exampleReducer,
};
export default {
register(app: StrapiApp) {
app.addReducers(reducers);
},
bootstrap() {},
};
使用 useSelector 读取状态
🌐 Reading state with useSelector
在你的插件组件中访问 Redux 状态最常见的方式是使用来自 react-redux 的 useSelector 钩子:
🌐 The most common way to access Redux state in your plugin components is using the useSelector hook from react-redux:
- JavaScript
- TypeScript
import { useSelector } from 'react-redux';
const HomePage = () => {
// Read current theme
const currentTheme = useSelector(
(state) => state.admin_app?.theme?.currentTheme
);
// Read current locale
const currentLocale = useSelector(
(state) => state.admin_app?.language?.locale
);
// Read authentication status
const isAuthenticated = useSelector((state) => !!state.admin_app?.token);
// Read available locales
const availableLocales = useSelector(
(state) => state.admin_app?.language?.localeNames || {}
);
return (
<div>
<p>Current Theme: {currentTheme}</p>
<p>Current Locale: {currentLocale}</p>
<p>Authenticated: {isAuthenticated ? 'Yes' : 'No'}</p>
</div>
);
};
import { useSelector } from 'react-redux';
const HomePage = () => {
// Read current theme
const currentTheme = useSelector(
(state: any) => state.admin_app?.theme?.currentTheme
);
// Read current locale
const currentLocale = useSelector(
(state: any) => state.admin_app?.language?.locale
);
// Read authentication status
const isAuthenticated = useSelector((state: any) => !!state.admin_app?.token);
// Read available locales
const availableLocales = useSelector(
(state: any) => state.admin_app?.language?.localeNames || {}
);
return (
<div>
<p>Current Theme: {currentTheme}</p>
<p>Current Locale: {currentLocale}</p>
<p>Authenticated: {isAuthenticated ? 'Yes' : 'No'}</p>
</div>
);
};
可用状态属性
🌐 Available state properties
admin_app 切片包含以下状态属性:
🌐 The admin_app slice contains the following state properties:
| 属性 | 类型 | 描述 ||---|---|---|| theme.currentTheme | string | 当前主题 ('light'、'dark' 或 'system') || theme.availableThemes | string[] | 可用主题名称数组 || language.locale | string | 当前语言代码(例如,'en'、'fr') || language.localeNames | object | 将语言代码映射到显示名称的对象 || token | string \| null | 认证令牌 || permissions | object | 用户权限对象 |
派发动作
🌐 Dispatching actions
要更新 Redux 存储,请使用 useDispatch 钩子:
🌐 To update the Redux store, use the useDispatch hook:
下面的示例为了说明用途,将操作分发到核心管理状态(主题、语言环境)。在实际操作中,大多数插件应将操作分发到它们自己的自定义 reducer,而不是修改全局管理状态。
🌐 The examples below dispatch actions to core admin state (theme, locale) for illustration purposes. In practice, most plugins should dispatch actions to their own custom reducers rather than modifying global admin state.
- JavaScript
- TypeScript
import { useSelector, useDispatch } from 'react-redux';
const HomePage = () => {
const dispatch = useDispatch();
const currentTheme = useSelector(
(state) => state.admin_app?.theme?.currentTheme
);
const handleToggleTheme = () => {
const newTheme =
currentTheme === 'light'
? 'dark'
: currentTheme === 'dark'
? 'system'
: 'light';
dispatch({
type: 'admin/setAppTheme',
payload: newTheme,
});
};
const handleChangeLocale = (locale) => {
dispatch({
type: 'admin/setLocale',
payload: locale,
});
};
return (
<div>
<button onClick={handleToggleTheme}>
Toggle Theme (Current: {currentTheme})
</button>
<button onClick={() => handleChangeLocale('en')}>Set English</button>
</div>
);
};
import { useSelector, useDispatch } from 'react-redux';
const HomePage = () => {
const dispatch = useDispatch();
const currentTheme = useSelector(
(state: any) => state.admin_app?.theme?.currentTheme
);
const handleToggleTheme = () => {
const newTheme =
currentTheme === 'light'
? 'dark'
: currentTheme === 'dark'
? 'system'
: 'light';
dispatch({
type: 'admin/setAppTheme',
payload: newTheme,
} as any);
};
const handleChangeLocale = (locale: string) => {
dispatch({
type: 'admin/setLocale',
payload: locale,
} as any);
};
return (
<div>
<button onClick={handleToggleTheme}>
Toggle Theme (Current: {currentTheme})
</button>
<button onClick={() => handleChangeLocale('en')}>Set English</button>
</div>
);
};
可用操作
🌐 Available actions
admin_app 切片提供以下操作:
🌐 The admin_app slice provides the following actions:
| 操作类型 | 载荷类型 | 描述 ||---|---|---|| admin/setAppTheme | string | 设置主题('light'、'dark' 或 'system') || admin/setAvailableThemes | string[] | 更新 admin_app 中的 theme.availableThemes || admin/setLocale | string | 设置语言环境(例如 'en'、'fr') || admin/setToken | string \| null | 设置认证令牌 || admin/login | { token: string, persist?: boolean } | 使用令牌和持久化选项的登录操作 || admin/logout | void | 登出操作(无载荷) |
在分发操作时,使用 Redux Toolkit 操作类型格式:'sliceName/actionName'。管理员切片名为 'admin',因此操作遵循模式 'admin/actionName'。
🌐 When dispatching actions, use the Redux Toolkit action type format: 'sliceName/actionName'. The admin slice is named 'admin', so actions follow the pattern 'admin/actionName'.
访问存储实例
🌐 Accessing the store instance
对于高级用例,你可以使用 useStore 钩子直接访问存储实例:
🌐 For advanced use cases, you can access the store instance directly using the useStore hook:
- JavaScript
- TypeScript
import { useStore } from 'react-redux';
import { useEffect } from 'react';
const App = () => {
const store = useStore();
useEffect(() => {
const state = store.getState();
console.log('Redux Store State:', state);
const unsubscribe = store.subscribe(() => {
const currentState = store.getState();
console.log('Store state changed:', {
theme: currentState.admin_app?.theme?.currentTheme,
locale: currentState.admin_app?.language?.locale,
timestamp: new Date().toISOString(),
});
});
return () => {
unsubscribe();
};
}, [store]);
return <div>My Plugin</div>;
};
import { useStore } from 'react-redux';
import { useEffect } from 'react';
const App = () => {
const store = useStore();
useEffect(() => {
const state = store.getState();
console.log('Redux Store State:', state);
const unsubscribe = store.subscribe(() => {
const currentState = store.getState();
console.log('Store state changed:', {
theme: currentState.admin_app?.theme?.currentTheme,
locale: currentState.admin_app?.language?.locale,
timestamp: new Date().toISOString(),
});
});
return () => {
unsubscribe();
};
}, [store]);
return <div>My Plugin</div>;
};
完整示例
🌐 Complete example
以下示例结合了本页描述的所有三种模式(useSelector、useDispatch、useStore):
🌐 The following example combines all 3 patterns (useSelector, useDispatch, useStore) described on the present page:
- JavaScript
- TypeScript
最佳实践
🌐 Best practices
- 使用
useSelector来读取状态。 相较于直接访问 store,更推荐使用useSelector。它会自动订阅更新,并在所选状态变化时重新渲染组件。 - 清理订阅。 始终在
useEffect清理函数中取消订阅存储订阅,以防止内存泄漏。 - 考虑类型安全。 在插件中访问 Redux 状态时,使用带有插件本地类型的
react-redux钩子(例如useSelector、useDispatch)(例如RootState和AppDispatch)。如果使用 Strapi 管理工具,请从@strapi/admin/strapi-admin导入它们(而不是@strapi/admin)。在它们明确被记录为稳定之前,避免依赖未记录的带类型的 Redux 钩子作为 Strapi 的公共 API。 - 避免不必要的分发。 只有在需要更新状态时才分发操作。读取状态不需要分发操作。
- 尊重核心状态。 修改核心管理状态(如主题或语言环境)时要小心,因为这会影响整个管理面板。请考虑你的插件是否应该修改全局状态,还是保持自己的本地状态。
要将你自己的状态添加到 Redux 存储中,请参阅上面的 添加自定义 reducer。
🌐 To add your own state to the Redux store, see Adding custom reducers above.