Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

baobab-deku #362

Open
Yomguithereal opened this issue Jan 5, 2016 · 11 comments
Open

baobab-deku #362

Yomguithereal opened this issue Jan 5, 2016 · 11 comments

Comments

@Yomguithereal
Copy link
Contributor

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 a branch function which is a higher order component and binds props of the given components to some part of the tree.

@Yomguithereal
Copy link
Contributor Author

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();

@troch
Copy link

troch commented Jan 5, 2016

👍 looks nice

@ashaffer
Copy link

ashaffer commented Jan 5, 2016

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?

@Yomguithereal
Copy link
Contributor Author

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.

@Yomguithereal
Copy link
Contributor Author

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.

@rstacruz
Copy link
Collaborator

rstacruz commented Jan 5, 2016

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.

@Yomguithereal
Copy link
Contributor Author

Thanks @rstacruz. I forgot to pass the tree in context indeed.

@Yomguithereal
Copy link
Contributor Author

What do you mean to work like react-redux's connect()?

@rstacruz
Copy link
Collaborator

rstacruz commented Jan 7, 2016

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 }
}

@Yomguithereal
Copy link
Contributor Author

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.

@anthonyshort
Copy link
Owner

Might be good to get this into the docs to show an approach using immutable structures instead of Redux :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants