|
export default class AppState {
|
|
constructor(initialState = {}, reducers = {}) {
|
|
this._state = { ...initialState };
|
|
this._reducers = reducers;
|
|
this._subscribers = new Set();
|
|
this._middlewares = [];
|
|
this._history = [{ ...initialState }];
|
|
this._historyIndex = 0;
|
|
}
|
|
|
|
use(middleware) {
|
|
this._middlewares.push(middleware);
|
|
return this;
|
|
}
|
|
|
|
subscribe(callback) {
|
|
this._subscribers.add(callback);
|
|
return () => this._subscribers.delete(callback);
|
|
}
|
|
|
|
getState() {
|
|
return { ...this._state };
|
|
}
|
|
|
|
setState(updates) {
|
|
const prevState = this.getState();
|
|
this._state = { ...this._state, ...updates };
|
|
|
|
this._history = this._history.slice(0, this._historyIndex + 1);
|
|
this._history.push({ ...this._state });
|
|
this._historyIndex++;
|
|
|
|
this._notifySubscribers(prevState, { type: 'STATE_UPDATE', payload: updates });
|
|
}
|
|
|
|
async dispatch(action) {
|
|
let processedAction = action;
|
|
|
|
for (const middleware of this._middlewares) {
|
|
processedAction = await middleware(processedAction, this.getState(), this);
|
|
if (!processedAction) return;
|
|
}
|
|
|
|
const { type, payload } = processedAction;
|
|
const reducer = this._reducers[type];
|
|
|
|
if (!reducer) {
|
|
console.warn(`No reducer for action: ${type}`);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const prevState = this.getState();
|
|
const newState = reducer(prevState, payload);
|
|
this._state = { ...newState };
|
|
|
|
this._history = this._history.slice(0, this._historyIndex + 1);
|
|
this._history.push({ ...this._state });
|
|
this._historyIndex++;
|
|
|
|
this._notifySubscribers(prevState, processedAction);
|
|
} catch (error) {
|
|
console.error(`Reducer error for ${type}:`, error);
|
|
}
|
|
}
|
|
|
|
undo() {
|
|
if (this._historyIndex > 0) {
|
|
this._historyIndex--;
|
|
this._state = { ...this._history[this._historyIndex] };
|
|
this._notifySubscribers(null, { type: 'UNDO' });
|
|
}
|
|
}
|
|
|
|
redo() {
|
|
if (this._historyIndex < this._history.length - 1) {
|
|
this._historyIndex++;
|
|
this._state = { ...this._history[this._historyIndex] };
|
|
this._notifySubscribers(null, { type: 'REDO' });
|
|
}
|
|
}
|
|
|
|
_notifySubscribers(prevState, action) {
|
|
this._subscribers.forEach(callback => {
|
|
try {
|
|
callback(this.getState(), prevState, action);
|
|
} catch (error) {
|
|
console.error('Subscriber error:', error);
|
|
}
|
|
});
|
|
}
|
|
}
|