autoscale: true
Getting started with S.js
import s from 's-js'
// create signal
const a = s.value(0)
// construct computation ('derived signal')
const b = s(() => a() + 1)
console.log(b()) // => 1
// change signal value
a(1)
// computation updates automatically
console.log(b()) // => 2
Reactive + Functional = S.js + pick you poison (mine is Ramda)
No need to reinvent the wheel!
RxJS, Bacon, Kefir, most etc.
They might have super powers.
But sometimes, we just need wheels.
Simple state management1
- Duplicate everything?
- Parameterize everything?
- But what about separation of concerns?
const s1 = s.data(0)
const s2 = s.data(1)
const Counter = ({ signal }) => <div>
<h2>Count: {signal()}</h2>
<button onClick={() => signal(signal() + 1)}>+</button>
</div>
const App = () => <div>
<Counter signal={s1} />
<Counter signal={s2} />
<Counter signal={s2} />
</div>
s.root(() =>
s.on([s1, s2], () => render(<App />, document.getElementById('root')))
)
const CounterPresentation = ({ value, onIncrement }) => <div>
<h2>Count: {value}</h2>
<button onClick={onIncrement}>+</button>
</div>
const Counter = ({ signal }) =>
<CounterPresentation
value={signal()}
onIncrement={() => signal(signal() + 1)}
/>
const connect = mapOwnProps => re.compose(
re.lifecycle({
componentDidMount() {
s(() => this.setState(mapOwnProps(this.props)))
}
}),
re.mapProps(mapOwnProps)
)
const Counter = z.connect(own => ({
value: own.signal(),
onIncrement: () => z.over(r.inc, own.signal)
}))(CounterPresentation)
if (localStorage.counter)
s1(localStorage.counter)
s.root(() =>
s(() => (localStorage.counter = s1())))
We lose
- dev tools
- middleware
- Although, how much of it do we still need?
But we gain
- no cruft
- degrees of freedom for simplicity/optimized performance
- modularity
- keep our familiar tools, no need to learn entirely new API
- S.js API is tiny
Footnotes
-
Gernot Höflechner’s talk “You don’t need state management” really struck a chord with me. He is onto something. Maybe we really can push all state to the boundaries. ↩