packages/docs/docs/editor-starter/state-management.mdx
State in the Editor Starter is managed with the built-in React state management utilities: useState() and useContext().
The whole state of the Editor Starter is stored in a single object with the shape defined by the EditorState.
type DeletedAsset = {
remoteUrl: string | null;
remoteFileKey: string | null;
assetId: string;
statusAtDeletion: AssetState;
};
export type UndoableState = {
tracks: TrackType[];
assets: Record<string, EditorStarterAsset>;
items: Record<string, EditorStarterItem>;
fps: number;
compositionWidth: number;
compositionHeight: number;
deletedAssets: DeletedAsset[];
};
export type EditorState = {
undoableState: UndoableState;
selectedItems: string[];
textItemEditing: string | null;
textItemHoverPreview: TextItemHoverPreview | null;
itemSelectedForCrop: string | null;
renderingTasks: RenderingTask[];
captioningTasks: CaptioningTask[];
initialized: boolean;
itemsBeingTrimmed: ItemBeingTrimmed[];
loop: boolean;
assetStatus: Record<string, AssetState>;
};
undoableState - State that is affected by the undo stack:
tracks: An array of timeline tracks, the last ones are the ones rendered in the back.assets: A map of all assets that have been uploaded to the editor.items: A map of all items that have been added to the editor.fps: The frame rate (kept in state, but by default no UI is exposed to change it).compositionWidth: The width of the canvas.compositionHeight: The height of the canvas.deletedAssets: An array of assets that have been deleted.selectedItems: An array of item IDs that are currently selected.textItemEditing: The ID of the text item that is currently being edited, if there is one.textItemHoverPreview: Preview updates of a text item (for example if a font is hovered in the font picker, the text will render temporarily with the font hovered).itemSelectedForCrop: The ID of the item that is currently in Crop Mode, if there is one.renderingTasks: The state of the rendering process.captioningTasks: The state of captioning process.initialized: Whether the editor has been initialized, if not initialized, canvas will not be visible.itemsBeingTrimmed: An array of items that are currently being trimmed, to show an indication of the maximum trim that is possible.loop: Whether the playback should loop.assetStatus: A map of asset IDs to their upload status, which can be:
pending-upload: The asset is currently being uploaded.uploaded: The asset has been uploaded successfully.error: The asset upload has failed.in-progress: The asset has not been uploaded yet.State is separated into undoable and non-undoable parts.
Undoable state is located within the undoableState object of the root state.
Undoable state might be:
Non-undoable state might be:
See also: Undo and Redo
In src/editor-context-provider.tsx, you will see a very deeply nested tree of various context providers.
This is intentional and achieves that when updating a portion of the state, only the components that are dependent on that portion of the state will re-render, while the rest of the components will not.
For the best performance, we recommend that you continue to use this pattern in your own application.
You should prevent an unnecessary state update when nothing has changed.
Throughout the codebase, you will see checks that prevent an unnecessary state update.
export const markAsDragging = (state: EditorState, itemId: string): EditorState => {
return changeItem(state, itemId, (item) => {
if (item.isDragging) {
// The item would not change, so we return the original object
return item;
}
return {
...item,
isDragging: true,
};
});
};
If you only need to access the state upon an interaction, you can use the useCurrentStateAsRef() hook.
It allows you to imperatively access the state when you need it.
You cannot build a reactive UI with it, but is more performant than using a hook that re-renders when the state changes.
For example: A save button that only needs to access the state when the user clicks it.