frontend-hamroun
Version:
A lightweight frontend JavaScript framework with React-like syntax
99 lines (98 loc) • 2.85 kB
JavaScript
/**
* Global state management solution similar to Redux
*/
import { useState, useEffect } from './hooks.js';
import { createContext, useContext } from './context.js';
import { jsx } from './jsx-runtime.js';
export function createStore(reducer, initialState, middlewares = []) {
let state = initialState;
let listeners = [];
// Apply middlewares
let dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
return action;
};
// Chain middlewares
if (middlewares.length > 0) {
const middlewareAPI = {
getState: () => state,
dispatch: (action) => dispatch(action),
subscribe: (listener) => subscribe(listener)
};
const chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = chain.reduce((a, b) => (next) => a(b(next)))(dispatch);
}
// Subscribe to store changes
function subscribe(listener) {
listeners.push(listener);
return function unsubscribe() {
listeners = listeners.filter(l => l !== listener);
};
}
// Initialize store with default state
dispatch({ type: '@@INIT' });
return {
getState: () => state,
dispatch,
subscribe
};
}
export const StoreContext = createContext({
store: {
getState: () => ({}),
dispatch: () => { },
subscribe: () => () => { }
},
state: {}
});
export function StoreProvider({ store, children }) {
const [state, setState] = useState(store.getState());
useEffect(() => {
const unsubscribe = store.subscribe(() => {
setState(store.getState());
});
return unsubscribe;
}, [store]);
return jsx(StoreContext.Provider, {
value: { store, state },
children
});
}
export function useSelector(selector) {
const context = useContext(StoreContext);
return selector(context.state);
}
export function useDispatch() {
const context = useContext(StoreContext);
return context.store.dispatch;
}
export function useStore() {
const context = useContext(StoreContext);
return context.store;
}
// Common middlewares
export const logger = (store) => (next) => (action) => {
console.group(action.type);
console.log('Previous state:', store.getState());
console.log('Action:', action);
const result = next(action);
console.log('Next state:', store.getState());
console.groupEnd();
return result;
};
export const thunk = (store) => (next) => (action) => {
if (typeof action === 'function') {
return action(store.dispatch, store.getState);
}
return next(action);
};
export default {
createStore,
StoreProvider,
useSelector,
useDispatch,
useStore,
logger,
thunk
};