editor.js/src/components/store/createStore.ts
Ilya Moroz e6db8d5140
[Feature] Add state manager (#2018)
* add state manager with demo file

* remove initial state

* move Store type to Store.ts

* add new actions

* change store schema

* add docs

* type -> interface, add deepCopy function

* move types to the /types/ folder

* rename types files, change state type (add blocks: key)

* fix createStore.ts func

* add documentation for reducer

* use BlockMutationType instead of ActionType

* add doc

* deep copy of initial state

* add doc for createStore

* Apply suggestions from code review

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>

* rename `reducer` to `blocksReducer`

* add a listener type, pass changed state to the listener

Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
2022-05-05 14:26:04 +03:00

68 lines
2 KiB
TypeScript

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;