Created
July 9, 2021 04:57
-
-
Save ronnycoding/1aad4d4205a6d2d02842a23e594f9103 to your computer and use it in GitHub Desktop.
React Patterns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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