93 lines
2.7 KiB
JavaScript
Raw Normal View History

2025-11-11 01:05:13 +01:00
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);
}
});
}
}