Skip to content

Instantly share code, notes, and snippets.

@ronnycoding
Created July 9, 2021 04:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ronnycoding/1aad4d4205a6d2d02842a23e594f9103 to your computer and use it in GitHub Desktop.
Save ronnycoding/1aad4d4205a6d2d02842a23e594f9103 to your computer and use it in GitHub Desktop.
React Patterns
// state reducer
// 💯 state reducer action types
import * as React from 'react'
import {Switch} from '../switch'
const callAll = (...fns) => (...args) => fns.forEach(fn => fn?.(...args))
const actionTypes = {
toggle: 'toggle',
reset: 'reset',
}
function toggleReducer(state, {type, initialState}) {
switch (type) {
case actionTypes.toggle: {
return {on: !state.on}
}
case actionTypes.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: actionTypes.toggle})
const reset = () => dispatch({type: actionTypes.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, actionTypes}
// import {useToggle, toggleReducer, actionTypes} from './use-toggle'
function App() {
const [timesClicked, setTimesClicked] = React.useState(0)
const clickedTooMuch = timesClicked >= 4
function toggleStateReducer(state, action) {
if (action.type === actionTypes.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