Skip to content

Instantly share code, notes, and snippets.

@ronnycoding
Created July 9, 2021 04:56
Show Gist options
  • Save ronnycoding/0beace4e32a16714b435205c9b84bbd3 to your computer and use it in GitHub Desktop.
Save ronnycoding/0beace4e32a16714b435205c9b84bbd3 to your computer and use it in GitHub Desktop.
React Patterns
// state reducer
// 💯 default state reducer
import * as React from 'react'
import {Switch} from '../switch'
const callAll = (...fns) => (...args) => fns.forEach(fn => fn?.(...args))
function toggleReducer(state, {type, initialState}) {
switch (type) {
case 'toggle': {
return {on: !state.on}
}
case 'reset': {
return initialState
}
default: {
throw new Error(`Unsupported type: ${type}`)
}
}
}
function useToggle({initialOn = false, reducer = toggleReducer} = {}) {
const {current: initialState} = React.useRef({on: initialOn})
const [state, dispatch] = React.useReducer(reducer, initialState)
const {on} = state
const toggle = () => dispatch({type: 'toggle'})
const reset = () => dispatch({type: 'reset', initialState})
function getTogglerProps({onClick, ...props} = {}) {
return {
'aria-pressed': on,
onClick: callAll(onClick, toggle),
...props,
}
}
function getResetterProps({onClick, ...props} = {}) {
return {
onClick: callAll(onClick, reset),
...props,
}
}
return {
on,
reset,
toggle,
getTogglerProps,
getResetterProps,
}
}
// export {useToggle, toggleReducer}
// import {useToggle, toggleReducer} from './use-toggle'
function App() {
const [timesClicked, setTimesClicked] = React.useState(0)
const clickedTooMuch = timesClicked >= 4
function toggleStateReducer(state, action) {
if (action.type === 'toggle' && clickedTooMuch) {
return {on: state.on}
}
return toggleReducer(state, action)
}
const {on, getTogglerProps, getResetterProps} = useToggle({
reducer: toggleStateReducer,
})
return (
<div>
<Switch
{...getTogglerProps({
disabled: clickedTooMuch,
on: on,
onClick: () => setTimesClicked(count => count + 1),
})}
/>
{clickedTooMuch ? (
<div data-testid="notice">
Whoa, you clicked too much!
<br />
</div>
) : timesClicked > 0 ? (
<div data-testid="click-count">Click count: {timesClicked}</div>
) : null}
<button {...getResetterProps({onClick: () => setTimesClicked(0)})}>
Reset
</button>
</div>
)
}
export default App
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment