docs/development/state-management/state-management-selectors.mdx
Selectors are data retrieval modules under the LobeHub data flow development framework. Their role is to extract data from the store using specific business logic for consumption by components.
Taking src/store/plugin/selectors.ts as an example:
This TypeScript code snippet defines an object named pluginSelectors, which contains a series of selector functions used to retrieve data from the plugin storage state. Selectors are functions that extract and derive data from a Redux store (or similar state management library). This specific example is for managing the state related to the frontend application's plugin system.
Here are some key points to note:
enabledSchema: A function that returns an array of ChatCompletionFunctions filtered based on the enabled plugin list enabledPlugins. It appends the plugin identifier as a prefix to the API names to ensure uniqueness and uses the uniqBy function from the es-toolkit library to remove duplicates.onlinePluginStore: Returns the current online plugin list.pluginList: Returns the list of plugins, including custom plugins and standard plugins.getPluginMetaById: Returns the plugin metadata based on the plugin ID.getDevPluginById: Returns information about the custom plugins in development.getPluginManifestById: Returns the plugin manifest based on the plugin ID.getPluginSettingsById: Returns the plugin settings based on the plugin ID.getPluginManifestLoadingStatus: Returns the loading status of the plugin manifest (loading, success, or error) based on the plugin ID.isCustomPlugin: Checks if the plugin with the given ID is a custom plugin.displayPluginList: Returns a processed plugin list, including author, avatar, creation time, description, homepage URL, identifier, and title.hasPluginUI: Determines if the plugin has UI components based on the plugin ID.Selectors are highly modular and maintainable. By encapsulating complex state selection logic in separate functions, they make the code more concise and intuitive when accessing state data in other parts of the application. Additionally, by using TypeScript, each function can have clear input and output types, which helps improve code reliability and development efficiency.
Taking the displayPluginList method as an example, its code is as follows:
const pluginList = (s: PluginStoreState) => [...s.pluginList, ...s.customPluginList];
const displayPluginList = (s: PluginStoreState) =>
pluginList(s).map((p) => ({
author: p.author,
avatar: p.meta?.avatar,
createAt: p.createAt,
desc: pluginHelpers.getPluginDesc(p.meta),
homepage: p.homepage,
identifier: p.identifier,
title: pluginHelpers.getPluginTitle(p.meta),
}));
pluginList method: Used to retrieve the list of all plugins from the plugin state storage PluginStoreState. It creates a new plugin list by combining two arrays: pluginList and customPluginList.displayPluginList method: Calls the pluginList method to retrieve the merged plugin list and transforms the title and desc into text displayed on the UI.In components, the final consumed data can be directly obtained by importing:
import { usePluginStore } from '@/store/plugin';
import { pluginSelectors } from '@/store/plugin/selectors';
const Render = ({ plugins }) => {
const list = usePluginStore(pluginSelectors.displayPluginList);
return <> ...
</>;
};
The benefits of implementing this approach are:
With this design, LobeHub developers can focus more on building the user interface and business logic without worrying about the details of data retrieval and processing. This pattern also provides better adaptability and scalability for potential future changes in state structure.