diff --git a/src/components/store/blocksReducer.ts b/src/components/store/blocksReducer.ts
new file mode 100644
index 00000000..8a0c7ea8
--- /dev/null
+++ b/src/components/store/blocksReducer.ts
@@ -0,0 +1,29 @@
+import { EditorState } from '../../../types/store/editorState';
+import { Action } from '../../../types/store/action';
+import * as _ from '../utils';
+import { BlockMutationType } from '../../../types/events/block/mutation-type';
+
+/**
+ * The reducer function for Editor.js state
+ * This function applies the passed action to the current state and returns the new state
+ * This reducer is especially for working with blocks data
+ *
+ * @param state - previous state to apply action
+ * @param action - information about the action in the previous state
+ */
+export default function blocksReducer(state: EditorState, action: Action): EditorState {
+ const stateCopy = _.deepCopy(state);
+
+ switch (action.type) {
+ case BlockMutationType.Added:
+ case BlockMutationType.Changed:
+ stateCopy.blocks[action.data.id] = action.data;
+ break;
+
+ case BlockMutationType.Removed:
+ delete stateCopy.blocks[action.blockId];
+ break;
+ }
+
+ return stateCopy;
+}
diff --git a/src/components/store/createStore.ts b/src/components/store/createStore.ts
new file mode 100644
index 00000000..adfd0e38
--- /dev/null
+++ b/src/components/store/createStore.ts
@@ -0,0 +1,67 @@
+import { EditorState } from '../../../types/store/editorState';
+import { Reducer } from '../../../types/store/reducer';
+import { Action } from '../../../types/store/action';
+import { Store } from '../../../types/store/store';
+import * as _ from '../utils';
+import { Listener } from '../../../types/store/listener';
+
+/**
+ * This function is an entry point to use the store in the editor
+ * It creates the store with an initial state
+ *
+ * It returns functions to use the store:
+ * subscribe - function for subscribing to each state change
+ * dispatch - function for applying actions to the store
+ * getState - function returns a current state of the store
+ *
+ * @param reducer - the function that applies the passed action to the current state and returns the new state.
+ * Passing a reducer function to the `createStore` function helps
+ * to add new logic to the Store without changing the main logic of the Store.
+ *
+ * @param initialState - initial state of the store
+ */
+function createStore(reducer: Reducer, initialState: EditorState = { blocks: {} }): Store {
+ const currentReducer = reducer;
+ let state = _.deepCopy(initialState);
+ const currentListeners = [];
+
+ /**
+ * Function for subscribing on state changes
+ *
+ * @param listener - function, that will execute every state change
+ *
+ * @returns {() => void} unsubscribe function
+ */
+ const subscribe = (listener: Listener): (() => void) => {
+ currentListeners.push(listener);
+
+ return (): void => {
+ currentListeners.splice(currentListeners.indexOf(listener), 1);
+ };
+ };
+
+ /**
+ * Dispatch action on the current state
+ *
+ * @param action - action that will be dispatched
+ */
+ const dispatch = (action: Action): void => {
+ state = currentReducer(state, action);
+ currentListeners.forEach((listener) => {
+ listener(state);
+ });
+ };
+
+ /**
+ * Function returns current state
+ */
+ const getState = (): EditorState => state;
+
+ return {
+ subscribe,
+ dispatch,
+ getState,
+ };
+}
+
+export default createStore;
diff --git a/src/components/store/demo.ts b/src/components/store/demo.ts
new file mode 100644
index 00000000..b62e0576
--- /dev/null
+++ b/src/components/store/demo.ts
@@ -0,0 +1,79 @@
+import store from './index';
+import { BlockMutationType } from '../../../types/events/block/mutation-type';
+import { EditorState } from '../../../types/store/editorState';
+import { Listener } from '../../../types/store/listener';
+
+/**
+ * Handle changes with previous and current states
+ */
+const onDataChange = (): Listener => {
+ /**
+ * Initial state
+ */
+ let currentState = store.getState();
+
+ /**
+ * onChange handler
+ *
+ * @param changedState - changed state after dispatching
+ */
+ return (changedState: EditorState): void => {
+ const prevState = currentState;
+
+ currentState = changedState;
+
+ console.log('***');
+ console.log('Previous state:', prevState);
+ console.log('Current state:', currentState);
+ console.log('***');
+ };
+};
+
+const unsubscribeOnDataChange = store.subscribe(onDataChange());
+
+const block1 = {
+ id: '3JPEqh8_Wc',
+ type: 'header',
+ data: {
+ text: 'Editor.js',
+ level: 2,
+ },
+};
+
+const block2 = {
+ id: 'AsbMKCuatV',
+ type: 'paragraph',
+ data: {
+ text: 'Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.',
+ },
+};
+
+const block2Changed = {
+ id: 'AsbMKCuatV',
+ type: 'paragraph',
+ data: {
+ text: 'Hey. Meet the new Editor. On this page you can see it in action — try to edit this text.',
+ },
+};
+
+store.dispatch({
+ type: BlockMutationType.Added,
+ data: block1,
+});
+
+store.dispatch({
+ type: BlockMutationType.Added,
+ data: block2,
+});
+
+store.dispatch({
+ type: BlockMutationType.Changed,
+ data: block2Changed,
+});
+
+store.dispatch({
+ type: BlockMutationType.Removed,
+ blockId: block1.id,
+});
+
+unsubscribeOnDataChange();
diff --git a/src/components/store/index.ts b/src/components/store/index.ts
new file mode 100644
index 00000000..e0227d1e
--- /dev/null
+++ b/src/components/store/index.ts
@@ -0,0 +1,6 @@
+import blocksReducer from './blocksReducer';
+import createStore from './createStore';
+
+const store = createStore(blocksReducer);
+
+export default store;
diff --git a/src/components/utils.ts b/src/components/utils.ts
index e1e756f6..dfd43176 100644
--- a/src/components/utils.ts
+++ b/src/components/utils.ts
@@ -761,4 +761,27 @@ export function cacheable>(target: T): T {
+ if (target === null) {
+ return target;
+ }
+
+ if (typeof target === 'object' && target !== {}) {
+ const cp = { ...target };
+
+ Object.keys(cp).forEach(k => {
+ cp[k] = deepCopy(cp[k]);
+ });
+
+ return cp;
+ }
+
+ return target;
+}
diff --git a/types/store/action.ts b/types/store/action.ts
new file mode 100644
index 00000000..21b7948d
--- /dev/null
+++ b/types/store/action.ts
@@ -0,0 +1,34 @@
+import { OutputBlockData } from '../index';
+import { BlockMutationType } from '../events/block/mutation-type';
+
+/**
+ * Action for creating a new block in the editor
+ * This action will add the new block to the state
+ */
+interface CreateBlockAction {
+ type: BlockMutationType.Added;
+ data: OutputBlockData;
+}
+
+/**
+ * Action for changing data of an existing block
+ * This action will change block data in the state by its id
+ */
+interface ChangeBlockDataAction {
+ type: BlockMutationType.Changed;
+ data: OutputBlockData;
+}
+
+/**
+ * Action for removing a block from the editor
+ * This action will remove the block from the state by its id
+ */
+interface RemoveBlockAction {
+ type: BlockMutationType.Removed;
+ blockId: string;
+}
+
+/**
+ * Available action types
+ */
+export type Action = CreateBlockAction | ChangeBlockDataAction | RemoveBlockAction;
diff --git a/types/store/editorState.ts b/types/store/editorState.ts
new file mode 100644
index 00000000..21960cfe
--- /dev/null
+++ b/types/store/editorState.ts
@@ -0,0 +1,11 @@
+import { OutputBlockData } from '../index';
+
+/**
+ * Type of the state object
+ */
+export interface EditorState {
+ /**
+ * Data of blocks in the editor
+ */
+ blocks: Record;
+}
diff --git a/types/store/listener.ts b/types/store/listener.ts
new file mode 100644
index 00000000..b7936d12
--- /dev/null
+++ b/types/store/listener.ts
@@ -0,0 +1,9 @@
+import { EditorState } from './editorState';
+
+/**
+ * Listener function type
+ * This function uses subscribing to state changes
+ *
+ * @param changedState - changed state after dispatch action on the state
+ */
+export type Listener = (changedState: EditorState) => void;
diff --git a/types/store/reducer.ts b/types/store/reducer.ts
new file mode 100644
index 00000000..9466d73f
--- /dev/null
+++ b/types/store/reducer.ts
@@ -0,0 +1,7 @@
+import { EditorState } from './editorState';
+import { Action } from './action';
+
+/**
+ * Type of the function that applies the passed action to the current state and returns the new state
+ */
+export type Reducer = (state: EditorState, action: Action) => EditorState
diff --git a/types/store/store.ts b/types/store/store.ts
new file mode 100644
index 00000000..620f62f4
--- /dev/null
+++ b/types/store/store.ts
@@ -0,0 +1,29 @@
+import { Action } from './action';
+import { EditorState } from './editorState';
+import { Listener } from './listener';
+
+/**
+ * Store type contains functions for use it
+ */
+export interface Store {
+ /**
+ * Function for subscribing on state changes
+ *
+ * @param listener - function, that will execute every state change
+ *
+ * @returns {() => void} unsubscribe function
+ */
+ subscribe: (listener: Listener) => (() => void);
+
+ /**
+ * Dispatch action on the current state
+ *
+ * @param action - action that will be dispatched
+ */
+ dispatch: (action: Action) => void;
+
+ /**
+ * Function returns current state
+ */
+ getState: () => EditorState;
+}