helixbass / ad-hok-utils Goto Github PK
View Code? Open in Web Editor NEWA collection of helpers for ad-hok
License: MIT License
A collection of helpers for ad-hok
License: MIT License
It looks like currently the handlers added by addExtendedHandlers()
are discarding the return value from the existing handlers and never returning a value, which seems incorrect/undesirable if the existing handler has a meaningful return value
Currently I think isInitialRender
would be false in eg an addEffectOnMount()
(after the addIsInitialRender
in the chain) because it uses its own internal addEffectOnMount()
which would run first?
So if isInitialRender
should be true during other effects on mount, I think it'd have to eg update its ref during the second render cycle instead?
There are combinations of condition on which to branch (nullishness vs non-nullishness vs truthiness vs falsiness vs empty array vs null vs non-null vs undefined vs non-undefined) + renderNothing()
vs returns()
something
Might be ideal to optionally accept a returns
option to specify a returns()
instead of a default renderNothing()
? So then just expose eg branchIfNullish()
(aka suppressUnlessProp()
), branchUnlessNullish()
, branchIfTruthy()
, branchIfFalsy()
, branchIfEmpty()
, branchUnlessEmpty()
, branchIfNull()
, branchUnlessNull()
, branchIfUndefined()
, branchUnlessUndefined()
?
And do the expected type-narrowing (per discussion with @peterstuart, probably can't do type-narrowing for truthy or non-empty array? Although wouldn't truthy be able to at least be narrowed if the prop in question is an actual boolean
(via Exclude<TProp, false>
)?
Should include install instructions and docs for each helper
Wasn't sure the easiest pattern for testing intervals w/ React testing library?
Seems like it should at least be optional to derive addReducerOverProps()
's initial state from props
Should run linting + testing
Seems like to avoid version conflicts between the version of ad-hok used by the project and the internal ad-hok dependency of ad-hok-utils, it should not include its own version of ad-hok and should use a peer dependency instead?
"Shorthand" for common addStateHandlers()
pattern where it's just a boolean state prop and a "toggler" handler
Implementation from a project:
import {CurriedPropsAdder, addStateHandlers} from 'ad-hok'
type AddStateToggler = <
TProps,
TStateName extends string,
TTogglerName extends string
>(
stateName: TStateName,
togglerName: TTogglerName,
initialValue?: boolean
) => CurriedPropsAdder<
TProps,
{
[stateName in TStateName]: boolean
} &
{
[togglerName in TTogglerName]: () => void
}
>
const addStateToggler: AddStateToggler = (
stateName,
togglerName,
initialValue = false
) =>
addStateHandlers(
{
[stateName]: initialValue,
},
{
[togglerName]: ({[stateName]: stateValue}) => () => ({
[stateName]: !stateValue,
}),
}
) as any
export default addStateToggler
iirc I had the corresponding addThrottledHandler()
/addThrottledCopy()
helpers set up on some project
It seems like eg in a case where the ad-hok prop-adding type "fudging" (of using &
) isn't working (eg if you want to reuse an existing prop name in a non-narrowing way), you could follow that with a helper that forces that prop to a specified type?
Not sure if that would have to "infect" the resulting type with Omit
?
Seems like the rough alternative would be to expose alternate "honest" typings for the prop-adding ad-hok helpers?
Probably worth doing to avoid bundle size concerns
Extremely pedantic, but "cleanup" isn't a verb--"clean up" is.
Seems like the only tricky thing would be should it also manually add its own name (ie the base handler prop) to the list of dependencies that it's passed?
This appears to be working and is another nice declarative type-narrowing branch()
helper:
import { ReactElement } from 'react'
import { branch, returns, renderNothing } from 'ad-hok'
// https://stackoverflow.com/a/62097481/732366
type ExtractPredicateType<TTypePredicate> = TTypePredicate extends (
value: any
) => value is infer TPredicateType
? TPredicateType
: never
type BranchIfFailsPredicate = <
TProps extends {},
TPropName extends keyof TProps,
TTypePredicate extends (value: TProps[TPropName]) => boolean
>(
propName: TPropName,
typePredicate: TTypePredicate,
opts?: {
returns?: (props: TProps) => ReactElement<any, any> | null
}
) => (
props: TProps
) => TProps &
{
[propName in TPropName]: ExtractPredicateType<TTypePredicate>
}
export const branchIfFailsPredicate: BranchIfFailsPredicate = (
propName,
typePredicate,
opts
) =>
branch(
({ [propName]: propValue }) => !typePredicate(propValue as any),
opts?.returns ? returns(opts.returns) : renderNothing()
) as any
So eg branchIfFailsPredicate('foo', isString)
should result in a narrowed type for foo
of string
after it in the chain
A useful helper would be to add a declarative triggerRerender()
handler prop to the chain
This can be implemented by eg:
addStateHandlers(
{
count: 0
},
{
triggerRerender: ({count}) => () => ({
count: count + 1,
}),
}
),
cleanupProps('count')
Then another possibly-worth-including-here abstraction on top of this + addInterval()
would be eg addRerenderingEveryNSeconds(5)
?
Per usage on Sage and discussion with @peterstuart, a declarative helper for triggering key
-based remounting whenever certain props change is very useful
As opposed to the Sage implementation (which relied on serializing the specified props), it's a better idea to do an increment-a-counter-key
-when-props-change-effect approach, probably in combination with doing prop identity stabilization on behalf of the caller
So maybe target this signature (I'd be inclined to identity-stabilize by default but allow it to be opted out of if you want to avoid the extra cost of isEqual()
comparisons and are effectively taking responsibility for identity stabilization yourself):
addRemountingWhenPropsChange(['foo', 'bar'], {shouldStabilizeIdentity: false})
If we're only including the "static reducer" form of useReducer()
in ad-hok via addReducer()
, then makes sense to include a curried-over-props variant here (and explain/link to it from the ad-hok docs)?
Per discussion with @peterstuart, this seems like a good convention for saying "if prop namespace collisions happen here, it's fair game" (while in reality making it highly likely (along with helper-specific prop naming) that any collision will actually occur) + "this prop is internal"
I ran into a use case for branchIfTruthy()
(the opposite of branchIfFalsy()
). Probably wouldn't do any useful type-narrowing (I guess could narrow out true
) but would be a useful shorthand
addInterval()
's delay argument should definitely be able to be supplied as a function of props rather than just a static value
Implemented a working version in the Tersa app
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.