Skip to content

Commit e46b787

Browse files
committed
refactor: replace StoreConnector with direct state management implementation
1 parent 9fd754d commit e46b787

File tree

21 files changed

+1187
-222
lines changed

21 files changed

+1187
-222
lines changed

public/js/components/simple-counter.js

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
/**
22
* Simple Counter Component
3-
*
4-
* This demonstrates the simplified state management approach using the simple-state.js library.
5-
* It provides a much cleaner API compared to the current implementation.
3+
*
4+
* This demonstrates a simplified state management approach without using the StoreConnector.
65
*/
7-
import { createStore, StoreConnector } from '../../js/deps.js';
6+
import { createStore } from '../../js/deps.js';
87

98
// Create a store for our counter component
109
const counterStore = createStore('counter', {
1110
count: 0,
1211
theme: 'light'
1312
});
1413

15-
// Define the base component class
16-
class SimpleCounterBase extends HTMLElement {
14+
// Define the component class
15+
class SimpleCounter extends HTMLElement {
1716
constructor() {
1817
super();
1918
this.attachShadow({ mode: 'open' });
19+
this._storeUnsubscribe = null;
2020
}
2121

2222
connectedCallback() {
23+
// Subscribe to store changes
24+
this._storeUnsubscribe = counterStore.subscribe((state, property) => {
25+
this.render();
26+
27+
// Update document theme if theme property changed
28+
if (property === 'theme') {
29+
document.documentElement.setAttribute('data-theme', state.theme);
30+
}
31+
});
32+
33+
// Initial render
2334
this.render();
2435
this.setupEventListeners();
25-
26-
// Connect specific elements to state properties
27-
this.bindElement(
28-
this.shadowRoot.querySelector('.counter-value'),
29-
'count',
30-
(value) => `Counter: ${value}`
31-
);
32-
33-
// Connect the theme toggle button text
34-
this.bindElement(
35-
this.shadowRoot.querySelector('#theme-toggle'),
36-
'theme',
37-
(theme) => `Toggle Theme (Current: ${theme})`
38-
);
39-
40-
// Update the component's theme when the theme changes
41-
this.connect('theme', (state) => {
42-
this.shadowRoot.host.setAttribute('data-theme', state.theme);
43-
});
36+
}
37+
38+
disconnectedCallback() {
39+
// Unsubscribe from store changes
40+
if (this._storeUnsubscribe) {
41+
this._storeUnsubscribe();
42+
this._storeUnsubscribe = null;
43+
}
4444
}
4545

4646
render() {
@@ -118,12 +118,15 @@ class SimpleCounterBase extends HTMLElement {
118118
</div>
119119
</div>
120120
`;
121+
122+
// Update host attribute for theme
123+
this.setAttribute('data-theme', theme);
121124
}
122125

123126
setupEventListeners() {
124127
// Increment button
125128
this.shadowRoot.getElementById('increment').addEventListener('click', () => {
126-
// Direct state manipulation - much cleaner!
129+
// Direct state manipulation
127130
counterStore.state.count++;
128131
});
129132

@@ -143,16 +146,10 @@ class SimpleCounterBase extends HTMLElement {
143146
this.shadowRoot.getElementById('theme-toggle').addEventListener('click', () => {
144147
// Toggle theme with a simple assignment
145148
counterStore.state.theme = counterStore.state.theme === 'light' ? 'dark' : 'light';
146-
147-
// Update document theme
148-
document.documentElement.setAttribute('data-theme', counterStore.state.theme);
149149
});
150150
}
151151
}
152152

153-
// Create the connected component using the StoreConnector mixin
154-
const SimpleCounter = StoreConnector(counterStore)(SimpleCounterBase);
155-
156153
// Register the custom element
157154
customElements.define('simple-counter', SimpleCounter);
158155

public/js/components/state-example.js

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
/**
2-
* Example component demonstrating state manager integration
2+
* Example component demonstrating state management
33
*/
44
console.log('Loading state-example.js');
5-
import { createStateManager, createConnectedComponent } from '../modules/state-manager/dist/index.js';
6-
console.log('Imported createStateManager from state-manager module');
75

8-
// Create a state manager with initial state
9-
const stateManager = createStateManager({
6+
// Create a simple state object with a Proxy for reactivity
7+
const createSimpleState = (initialState = {}) => {
8+
const listeners = new Set();
9+
10+
const state = new Proxy(initialState, {
11+
set(target, property, value) {
12+
const oldValue = target[property];
13+
target[property] = value;
14+
15+
if (oldValue !== value) {
16+
listeners.forEach(listener => listener(value, property, target));
17+
}
18+
19+
return true;
20+
}
21+
});
22+
23+
return {
24+
state,
25+
subscribe(listener) {
26+
listeners.add(listener);
27+
return () => listeners.delete(listener);
28+
}
29+
};
30+
};
31+
32+
// Create a state store with initial state
33+
const stateStore = createSimpleState({
1034
counter: 0,
1135
theme: document.documentElement.getAttribute('data-theme') || 'light',
1236
user: { loggedIn: false }
13-
}, {
14-
enablePersistence: true,
15-
persistenceKey: 'state_example',
16-
debug: true
1737
});
1838

1939
// Define the component class
@@ -22,33 +42,50 @@ class StateExampleElement extends HTMLElement {
2242
super();
2343
console.log('StateExampleElement constructor called');
2444
this.attachShadow({ mode: 'open' });
45+
this._unsubscribe = null;
2546
}
2647

2748
connectedCallback() {
2849
console.log('StateExampleElement connected to DOM');
29-
this.render();
30-
}
31-
32-
/**
33-
* This method will be called when state changes
34-
* @param {object} state - The current state
35-
* @param {string} path - The path that changed
36-
* @param {object} fullState - The full state object
37-
*/
38-
stateChanged(state, path, fullState) {
39-
console.log('State changed in component:', path);
40-
console.log('New state:', fullState);
41-
console.log('State value:', state);
4250

43-
// Re-render the component
44-
this.render();
51+
// Subscribe to state changes
52+
this._unsubscribe = stateStore.subscribe((value, property, fullState) => {
53+
console.log('State changed in component:', property);
54+
console.log('New state:', fullState);
55+
console.log('State value:', value);
56+
57+
// Re-render the component
58+
this.render();
59+
60+
// If the theme changed, update the document theme
61+
if (property === 'theme') {
62+
document.documentElement.setAttribute('data-theme', value);
63+
}
64+
});
4565

46-
// If the theme changed, update the document theme
47-
if (path === 'theme') {
48-
document.documentElement.setAttribute('data-theme', state);
66+
this.render();
67+
}
68+
69+
disconnectedCallback() {
70+
// Clean up subscription when element is removed
71+
if (this._unsubscribe) {
72+
this._unsubscribe();
73+
this._unsubscribe = null;
4974
}
5075
}
5176

77+
// Helper method to get state
78+
getState(property) {
79+
return stateStore.state[property];
80+
}
81+
82+
// Helper method to set state
83+
setState(updates) {
84+
Object.entries(updates).forEach(([key, value]) => {
85+
stateStore.state[key] = value;
86+
});
87+
}
88+
5289
render() {
5390
// Get current values from state
5491
const counter = this.getState('counter') || 0;
@@ -212,9 +249,7 @@ class StateExampleElement extends HTMLElement {
212249
}
213250
}
214251

215-
// Register the component with the state manager
216-
createConnectedComponent('state-example', StateExampleElement, {
217-
statePaths: ['counter', 'theme', 'user']
218-
}, stateManager);
252+
// Register the custom element
253+
customElements.define('state-example', StateExampleElement);
219254

220255
export default StateExampleElement;

0 commit comments

Comments
 (0)