0.0.13-fixlogs.2 • Published 1 year ago
@rcharmeyer/react-utils v0.0.13-fixlogs.2
react-utils
My library of React utilities.
Hooks
Scopes & Hoisting State
Using createStore
const AccordionScope = createScope ()
const openIdStore = createStore (() => {
const [ openId, setOpenId ] = useState (null)
return { openId, setOpenId }
}, [ AccordionScope ])
function AccordionItem ({ id, children }) {
const { openId, setOpenId } = useStore (openIdStore)
const open = openId === id
const toggleOpen = useEvent (() => setOpenId (open ? null : id))
return (
<Expandable open={open} onToggle={toggleOpen}>
{children}
</Expandable>
)
}
Adding createStoreFamily
const AccordionScope = createScope ()
const openIdStore = createStore (() => {
const [ openId, setOpenId ] = useState (null)
return { openId, setOpenId }
}, [ AccordionScope ])
const openStoreBy = createStoreFamily ((id) => {
const { openId, setOpenId } = useStore (openIdStore)
const open = openId === id
const toggleOpen = useEvent (() => setOpenId (open ? null : id))
return { open, toggleOpen }
}, [ AccordionScope ])
function AccordionItem ({ id, children }) {
const { open, toggleOpen } = useStore (openStoreBy (id))
return (
<Expandable open={open} onToggle={toggleOpen}>
{children}
</Expandable>
)
}
Using hoist
instead of create
const AccordionScope = createScope ()
const useOpenIdState = hoist (() => {
const [ openId, setOpenId ] = useState (null)
return { openId, setOpenId }
}, [ AccordionScope ])
const useOpenToggleBy = hoist ((id) => {
const { openId, setOpenId } = useStore (openIdStore)
const open = openId === id
const toggleOpen = useEvent (() => setOpenId (open ? null : id))
return { open, toggleOpen }
}, [ AccordionScope ])
function AccordionItem ({ id, children }) {
const { open, toggleOpen } = useOpenToggleBy (id)
return (
<Expandable open={open} onToggle={toggleOpen}>
{children}
</Expandable>
)
}
Utilities
useEvent
Based on this React RFC of the same name.
This hook is a lot like useCallback
but it requires no deps because the
reference is always stable and always represents the latest callback. However,
unlike useCallback
it does not support returning values or async functions.
function Expandable ({ children }) {
const [ active, setActive ] = useState (false)
const toggleActive = useEvent (() => {
setActive (!active)
})
// Button never re-renders, not possible with useCallback
return <>
<Button onClick={toggleActive}>
{active && <div>{children}</div>}
</>
}
useStruct
// with useStruct
function useTuple (a, b) {
return useStruct ([ a, b ])
}
// without
function useTuple (a, b) {
return useMemo (() => {
return [a, b] as const
}, [a, b])
}
useMemoShallow
useMemo
except it will also check for shallow equality of the return value.
type Item = {
id: string,
tags: string[],
}
function useFilteredItems (items: Item[], tag: string) {
return useMemoShallow (() => {
return items.filter (item => item.tags.includes (tag))
}, [ items, tag ])
}