Open Yomguithereal opened 8 years ago
Here is the gist:
import Baobab from 'baobab';
import {dom, element} from 'deku';
import {createDispatcher, branch} from 'baobab-deku';
const {createRenderer} = dom;
// 1. Creating our tree
const tree = new Baobab({counter: 0});
// 2. Creating actions to mutate the counter
function increment(tree, by = 1) {
tree.apply('counter', nb => nb + by);
}
function decrement(tree, by = 1) {
tree.apply('counter', nb => nb - by);
}
// 3. Creating our dispatcher & renderer
const dispatcher = createDispatcher(tree),
render = createRenderer(document.body, dispatcher);
// 4. Creating a counter component
const Counter = branch({counter: ['counter']}, ({dispatch, props}) => {
return (
<div>
<p>{props.counter}</p>
<div>
<button onClick={dispatch(decrement)}>-</button>
<button onClick={dispatch(increment)}>+</button>
</div>
<div>
<button onClick={dispatch(decrement, 10)}>-10</button>
<button onClick={dispatch(increment, 10)}>+10</button>
</div>
</div>
);
});
// 5. Rendering our app, pass the tree as context & refreshing on tree update
function refresh() {
render(<Counter />, {tree});
}
tree.on('update', refresh);
refresh();
:+1: looks nice
This looks interesting. I think an approach like this using cursors might be the right one. However, it seems like a weird definition of dispatch
that you have here.
Why not dispatch into something like redux, and have your baobab tree updated in your reducer?
You could very dispatch data-actions like redux does and reduce them but the thing is Baobab enables imperative style updates and the actions aren't pure per se. It works more like Clojure's atom swapping like Om does, for instance.
One of the reason I went this way is because hot-reloading is free. You just need to hot-reload the rendering logic whereas with redux, as displayed here, you need to hot-reload both the rendering logic and the reducers.
Another solution, which is used by baobab-react is to partially apply the actions with the tree at component level, but this makes the higher order branch
more difficult to use for virtually no benefit.
this is neat, I'd probably have tried to pass the tree
to render(<Counter />, tree)
and made branch()
work like react-redux's connect() or something.
Thanks @rstacruz. I forgot to pass the tree in context indeed.
What do you mean to work like react-redux's connect()?
react-redux has a connect()
function that lets you select what part of the humongous state tree you want to use in the component:
module.exports = connect(map)(component)
function map (state) {
// return a slice of `state` that the component concerns itself with.
// it will be passed as props to the component.
return { number: state.number }
}
You don't need this with Baobab because the tree has cursors (which is very useful to handle humongous state trees).
This is what is done by:
const Counter = branch({counter: ['counter']}, Component);
It basically says, I want a prop to be named counter
and map data from the tree at path ['counter']
to it.
Plus, this is statically analyzable and enables (not yet with deku but with React it does) a re-render directly from relevant components.
Might be good to get this into the docs to show an approach using immutable structures instead of Redux :)
Hello deku. I've just started implementing a very simple helpers lib to use deku along with Baobab. You can think of it as a centralized app state store.
I am just starting a discussion here about the choices made and so I can maybe collect some feedback. It just has a
createDispatcher
function and very simple actions (that you can easily compose) and abranch
function which is a higher order component and binds props of the given components to some part of the tree.