Skip to content

Instantly share code, notes, and snippets.

@ProfAvery
Last active June 28, 2025 03:23
Show Gist options
  • Save ProfAvery/ccace6ffc6810d5749faab561fa0a090 to your computer and use it in GitHub Desktop.
Save ProfAvery/ccace6ffc6810d5749faab561fa0a090 to your computer and use it in GitHub Desktop.
Reducers without React - Summer 2025 AMSE Bootcamp
import { createStore } from 'redux'
const initialCartState = []
const CartTypes = {
ADD: 'ADD',
EMPTY: 'EMPTY',
REMOVE: 'REMOVE'
}
const findItem = (cart, itemId) => cart.find((item) => item.itemId === itemId)
const cartReducer = (state = initialCartState, action) => {
switch (action.type) {
case CartTypes.ADD:
if (findItem(state, action.itemId)) {
return state.map((item) => (item.itemId === action.itemId
? { ...item, quantity: item.quantity + 1 }
: item))
}
return [
...state,
{ itemId: action.itemId, quantity: 1 }
]
case CartTypes.EMPTY:
return []
case CartTypes.REMOVE:
return state.filter((item) => item.itemId !== action.itemId)
default:
return state
}
}
const store = createStore(cartReducer)
console.log.count = 0
store.subscribe(() => { console.log('State', console.log.count++, ':', store.getState()) })
console.log('Filling cart...')
store.dispatch({ type: CartTypes.ADD, itemId: 'coffee' })
store.dispatch({ type: CartTypes.ADD, itemId: 'coffee' })
store.dispatch({ type: CartTypes.ADD, itemId: 'cookie' })
console.log("\nMaybe I don't need a cookie...")
store.dispatch({ type: CartTypes.REMOVE, itemId: 'cookie' })
console.log('\nNever mind...')
store.dispatch({ type: CartTypes.EMPTY })
const initialCartState = []
const CartTypes = {
ADD: 'ADD',
EMPTY: 'EMPTY',
REMOVE: 'REMOVE'
}
const findItem = (cart, itemId) => cart.find((item) => item.itemId === itemId)
const cartReducer = (state, action) => {
switch (action.type) {
case CartTypes.ADD:
if (findItem(state, action.itemId)) {
return state.map((item) => (item.itemId === action.itemId
? { ...item, quantity: item.quantity + 1 }
: item))
}
return [
...state,
{ itemId: action.itemId, quantity: 1 }
]
case CartTypes.EMPTY:
return []
case CartTypes.REMOVE:
return state.filter((item) => item.itemId !== action.itemId)
default:
throw new Error(`Invalid action type ${action.type}`)
}
}
function traceReducer (reducer) {
let count = 0
return (state, action) => {
const nextState = reducer(state, action)
console.log('State', count++, ':', nextState)
return nextState
}
}
const tracedCartReducer = traceReducer(cartReducer)
console.log('Filling cart...')
const filledState = [
{ type: CartTypes.ADD, itemId: 'coffee' },
{ type: CartTypes.ADD, itemId: 'coffee' },
{ type: CartTypes.ADD, itemId: 'cookie' }
].reduce(tracedCartReducer, initialCartState)
console.log("\nMaybe I don't need a cookie...")
const noCookieState = [
{ type: CartTypes.REMOVE, itemId: 'cookie' }
].reduce(tracedCartReducer, filledState)
console.log('\nNever mind...')
const finalState = [
{ type: CartTypes.EMPTY }
].reduce(tracedCartReducer, noCookieState)
import { createStore, combineReducers } from 'redux'
const initialUserState = { authenticated: false }
const UserTypes = {
LOGIN: 'LOGIN',
LOGOUT: 'LOGOUT'
}
const userReducer = (state = initialUserState, action) => {
switch (action.type) {
case UserTypes.LOGIN:
if (action.username && action.password === 'pass') {
return { username: action.username, authenticated: true }
}
return { authenticated: false }
case UserTypes.LOGOUT:
return { authenticated: false }
default:
return state
}
}
const initialCartState = []
const CartTypes = {
ADD: 'ADD',
EMPTY: 'EMPTY',
REMOVE: 'REMOVE'
}
const findItem = (cart, itemId) => cart.find((item) => item.itemId === itemId)
const cartReducer = (state = initialCartState, action) => {
switch (action.type) {
case CartTypes.ADD:
if (findItem(state, action.itemId)) {
return state.map((item) => (item.itemId === action.itemId
? { ...item, quantity: item.quantity + 1 }
: item))
}
return [
...state,
{ itemId: action.itemId, quantity: 1 }
]
case CartTypes.EMPTY:
return []
case CartTypes.REMOVE:
return state.filter((item) => item.itemId !== action.itemId)
default:
return state
}
}
const rootReducer = combineReducers({
user: userReducer,
cart: cartReducer
})
const store = createStore(rootReducer)
console.log.count = 0
store.subscribe(() => { console.log('State', console.log.count++, ':', store.getState()) })
console.log('Filling cart...')
store.dispatch({ type: CartTypes.ADD, itemId: 'coffee' })
store.dispatch({ type: CartTypes.ADD, itemId: 'coffee' })
store.dispatch({ type: CartTypes.ADD, itemId: 'cookie' })
console.log('\nLogging in with wrong password...')
store.dispatch({ type: UserTypes.LOGIN, username: 'ProfAvery', password: 'wrong' })
console.log('\nLogging in...')
store.dispatch({ type: UserTypes.LOGIN, username: 'ProfAvery', password: 'pass' })
console.log("\nMaybe I don't need a cookie...")
store.dispatch({ type: CartTypes.REMOVE, itemId: 'cookie' })
console.log('\nNever mind...')
store.dispatch({ type: CartTypes.EMPTY })
console.log('\nLogging out...')
store.dispatch({ type: UserTypes.LOGOUT })
import { createSlice, configureStore } from '@reduxjs/toolkit'
const userSlice = createSlice({
name: 'user',
initialState: { authenticated: false },
reducers: {
login: (state, action) => {
if (action.payload.username && action.payload.password === 'pass') {
state.username = action.payload.username
state.authenticated = true
}
state.authenticated = false
},
logout: (state) => {
delete state.username
state.authenticated = false
}
}
})
const { login, logout } = userSlice.actions
const findItem = (cart, itemId) => cart.find((item) => item.itemId === itemId)
const cartSlice = createSlice({
name: 'cart',
initialState: [],
reducers: {
add: (state, action) => {
const item = findItem(state, action.payload.itemId)
if (item) {
item.quantity++
} else {
state.push({ itemId: action.payload.itemId, quantity: 1 })
}
},
empty: (state) => {
state.length = 0
},
remove: (state, action) => {
const index = state.findIndex((item) => item.itemId === action.payload.itemId)
if (index !== -1) {
state.splice(index, 1)
}
}
}
})
const { add, empty, remove } = cartSlice.actions
const store = configureStore({
reducer: {
user: userSlice.reducer,
cart: cartSlice.reducer
}
})
console.log.count = 0
store.subscribe(() => { console.log('State', console.log.count++, ':', store.getState()) })
console.log('Filling cart...')
store.dispatch(add({ itemId: 'coffee' }))
store.dispatch(add({ itemId: 'coffee' }))
store.dispatch(add({ itemId: 'cookie' }))
console.log('\nLogging in with wrong password...')
store.dispatch(login({ username: 'ProfAvery', password: 'wrong' }))
console.log('\nLogging in...')
store.dispatch(login({ username: 'ProfAvery', password: 'pass' }))
console.log("\nMaybe I don't need a cookie...")
store.dispatch(remove({ itemId: 'cookie' }))
console.log('\nNever mind...')
store.dispatch(empty())
console.log('\nLogging out...')
store.dispatch(logout())
{
"dependencies": {
"@reduxjs/toolkit": "^2.2.6",
"redux": "^5.0.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment