Usecase
For reusable components like that:
const Component = (props: ComponentProps) => ...
it would be desirable for ComponentProps
to have shape like that:
interface ComponentProps {
prop1: string | State<string>
prop2: number | State<number>
}
That is, while composing a Component object, you can pass in either a static string
object, or a state object for string
for prop1
, and either a static number
object, or a state object for number
for prop2
. In other words, the custom component can either be built statically, or reactively (whose appearance is reactive to underlying state changes).
If the property value is used as the child DOM node or property value of the tag function, everything will work properly. Since both child DOM node and property value can accept both static and state objects. However, when the property value is used in van.bind
or state-derived properties, things will be problematic, as both van.bind
and state-derived properties can only accept state objects, not static objects as deps
argument.
The example below illustrate the problematic situation:
const Button = (color: string | State<string>) => button(
{style: {deps: [color], f: color => `background-color: ${color};`}},
"Click me",
)
The code above works when color
is a string-typed state object, but doesn't work if color
is a string, as state-derived properties don't support static object as values of deps
argument.
Solution
Both van.bind
and state-derived properties should support both state and static objects as values of deps
argument. When a static object is passed in, the behavior would be the same as if a state object whose val
never changes.
Workaround before official solution is released
Before the official support is in place, VanJS users are encouraged to use the following workaround:
const stateProto = van.state(0).__proto__
const toState = v => v.__proto__ === stateProto ? v : van.state(v)
const Button = (color: string | State<string>) => button(
{style: {deps: [toState(color)], f: color => `background-color: ${color};`}},
"Click me",
)