Skip to content

Instantly share code, notes, and snippets.

@amsterdamharu
Last active October 3, 2022 12:53
Show Gist options
  • Save amsterdamharu/33f0fa989027328fe753589819b9db8e to your computer and use it in GitHub Desktop.
Save amsterdamharu/33f0fa989027328fe753589819b9db8e to your computer and use it in GitHub Desktop.
Simple implementation of Redux
const createSelectObservable = (() => {
let state;
let pReducer = (state, action) => state;
const subscribers = new Map();
const addSubscriber = (selector) => {
subscribers.set(selector, selector);
//return unsubscribe function
return () => subscribers.delete(selector);
};
const dispatch = (action) => {
state = pReducer(state, action);
subscribers.forEach((subscriber) => subscriber(state));
};
const getState = () => state;
return (reducer, initialState) => {
pReducer = reducer;
state = initialState;
return { addSubscriber, dispatch, getState };
};
})(); //IIFE
//createSelectObservable used in custom hook
const COUNTERS = 1000;
const ADD = 'COUNTERS_ADD';
const REMOVE = 'COUNTERS_REMOVE';
const initialState = Object.fromEntries(
[...new Array(COUNTERS)].map((_, index) => [index, 0])
);
const reducer = (state, { type, payload }) => {
if (type === ADD) {
return {
...state,
[payload]: state[payload] + 1,
};
}
if (type === REMOVE) {
const { [payload]: gone, ...rest } = state;
return rest;
}
return state;
};
const { addSubscriber, dispatch, getState } =
createSelectObservable(reducer, initialState);
const useCounter = (selector) => {
const [state, setState] = useState(selector(getState()));
useEffect(
() =>
addSubscriber((state) => setState(selector(state))),
[selector]
);
return state;
};
//components using the state
const Component = () => {
const counters = useCounter((s) => s);
return (
<ul>
{Object.entries(counters).map(([id, count]) => (
<Counter key={id} id={id} />
))}
</ul>
);
};
const Counter = React.memo(function Counter({ id }) {
const add = () => dispatch({ type: ADD, payload: id });
const remove = () =>
dispatch({ type: REMOVE, payload: id });
const selector = useCallback((state) => state[id], [id]);
const count = useCounter(selector);
return (
<li>
{id}: <button onClick={add}>{count}</button>
<button onClick={remove}>remove</button>
</li>
);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment