Last breaking change suggestion: Tags
See original GitHub issueWhen we first started using template tags with operators we wanted them initially to help express operators with a lot less internals (no parser or compiler). It also gave us the ability to compose paths:
state`foo.${input`bar`}`
This is super powerful stuff, but with the experience and late suggestions I think we made a mistake calling them “Operator tags”. With the latest suggested feature of router using:
{
path: '/:id',
map: {
id: input`id`
}
}
…operator tags is not the right name and scope for them. Also with suggestions on making connect work like:
connect({
foo: state`foo.path`,
someSignal: signal`some.signal`,
item: state`items.${props`itemKey`}`
})
I think we should make a change. This is breaking, but I think it is important that we make the change so “template tags” can live out their full potential.
Tags
We just call them tags, and there are 5 of them by default:
import {state, input, signal, props, string} from 'cerebral/tags';
Tags gives information to operators, connect, module options etc. about targeting something in Cerebral. It is a general concept that can be used with whatever.
Operators
import {state, input, string, signal} from 'cerebral/tags';
import {set} from 'cerebral/operators';
import showMessage from '../factories/showMessage';
export default [
set(state`foo`, input`foo`),
showMessage(string`Hi there ${state`user.name`}`),
httpGet('/something', {
progress: signal`some.signal`
})
]
Connect
import {state, signal, props} from 'cerebral/tags';
import {connect} from 'cerebral/react';
export default connect({
foo: state`foo.path`,
someSignal: signal`some.signal`,
item: state`items.${props`itemKey`}`
})
Router and other options
import {state, input, signal} from 'cerebral/tags';
const routes = [{
path: '/items/:id',
map: {
id: state`currentItemId`
}
}]
Other reasons
Documentation
In documentation we can explain **TAGS ** as a general concept for targeting things, not something specifically to operators. Operators becomes less “magic” that way.
Scalability
It is now safe to introduce new tags that does not necessarily have to do with operators
Dynamic state retrieval in components
An issue now is that you often need two components to grab state. An example:
connect(props => ({
item: `items.${props.currentItemKey}`
}))
The parent component has to depend on currentItemKey
for the child component to dynamically depend on it and optimize itself. This issue becomes even worse with a computed:
connect(props => ({
item: augmentedItem.props({itemKey: props.currentItemKey})
}))
Now there is a parent component -> child component -> computed dependency. With this new concept these two ones could be implemented as:
// Dynamic state deps
connect({
item: state`items.${state`currentItemKey`}`
}, ...)
// Computed, same thing
const augmentedItem = Computed({
item: state`items.${state`currentItemKey`}`
}, ...)
This is a huge deal in me opinion, cause it is difficult to reason about the component/computed dependency to get your shit done 😃
And yes… I know we stated no more breaking, but believe me. We have a pretty big refactor in our project to move to this… so when it comes to “is the juice worth the squeeze”, I am positive that it is 😃
Issue Analytics
- State:
- Created 7 years ago
- Reactions:7
- Comments:13 (13 by maintainers)
Top GitHub Comments
@gaspard
props
is used, notinput
. Tags are targets, so “Input” is not a valid target for connect, but it would be in a signal. Invalid target usage throws errors. Likesignal
is not a valid target for theset
operator@garth Jup, will be three args to connect. Extract stuff from Cerebral. State and signals. Second arg is the merge prop thingy. And last is component 😃
@maxfrigge Computed is a different discussion 😉 With this change computed works the way it does today