reflect
reflect copied to clipboard
Dynamic `bind` API
This RFC solves impossibility to combine @effector/reflect
and effector-factorio
, as well as adding protocol to integrate other dynamic bindings in a future
How does it look?
It looks like this:
import { reflect, take } from '@effector/reflect'
const SomeInput = reflect({
view: Input,
bind: {
value: take(something, key)
}
})
take
returns the following structure:
{
/** Telling `reflect` how to extract the dynamic source of units */
useSource: props => something.useSource(props),
/** `key` that takes unit from source */
key: key
}
In effector-factorio
we will add this alias:
factory.useSource = factory.useModel // Takes model instance from React.Context
And then we will be able to combine them:
const factory = modelFactory(() => {
return {
$value: createStore("")
}
})
const SomeInput = reflect({
view: Input,
bind: {
value: take(factory, "$value")
}
})
Also
- We should also support
(source, props) => key
variant forkey
in order to support dynamic factories (they're not welcome but technically possible) - We could also add
fromProps(key) === take({ useSource: props => props, key)
shorthand that allows to take store from just props
Why this API? Why not bind: props => ({ ... })
?
- No breaking changes
- We still statically get all non-dynamic bindings
- This API is not limited/specific for
effector-factorio
only, it doesn't even have its mention - Adds only 10 lines of code in
@effector/reflect
and 1 alias ineffector-factorio
There is a lot of ways in React to get dynamic data using hooks.
// Simple hook
const data = useHook();
// Hook with params
const data = useHook(params);
// Hook with callback
const data = useHook(() => new Class());
// Hook returning array
const [data] = useHook();
// Hook returning object
const {data} = useHook();
// Hook that depends on other hook data
const dataOne = useHookOne();
const dataTwo = useHookTwo(dataOne);
Also with your implementation if you use multiple keys from the factory
bind: {
value: take(factory, "$value"),
valueChange: take(factory, "valueChange")
}
The factory useModel()
will be called N
times, where N
is the amount of wanted keys.
It might be much more flexible to add a hook property that will gather all the data and then add it to a bind
values.
const SomeInput = reflect({
view: Input,
bind: {
value: $value
},
useDynamicBind: (componentProps) => {
const hookWithPropsData = useHook(componentProps.transactionId);
const hookThatDependsData = useDependentHook(hookWithPropsData);
const {$store, storeChange} = factory.useModel();
return { $store, storeChange, hookThatDependsData }
}
})
What about API like this?
const SomeInput = reflect({
view: Input,
bind: {
value: factory.fromModel((model) => model.$value),
},
})
But actually I think we can implement take(factory, 'key')
With factory.fromModel
factorio will know about reflect. And we'll also have to make the same for keyval and any other library 🤔
I think factory.fromModel
can return some internal object implement by protocol.
{
useSource: props => something.useSource(props),
fn: () => Unit
}