funkia / turbine

Purely functional frontend framework for building web applications
MIT License
686 stars 27 forks source link

Simplify the counter example? #50

Open dmitriz opened 7 years ago

dmitriz commented 7 years ago

This seems to look like the case for the loop: https://github.com/funkia/turbine/blob/master/examples/counters/src/index.ts#L44

That would remove the need for the model, right? There is the conversion from stream into behaviour in the model, I see where it comes from, but having one thing for both might possibly be simpler here? Then it would be just one short loop :)

The component itself looks like a general purpose selector component, to which you pass the array labels = [1, 2, 3, 4], along with the child component selectorButton.

I wonder if that can be made into something nice and reusable...

dmitriz commented 7 years ago

Here it might be nice to slightly overload the div, so you could simply pass the stream or behavior of component directly to div:

https://github.com/funkia/turbine/blob/master/examples/counters/src/index.ts#L59

I've thought that was also what happened here:

...
const {inputValue: email} = yield input();
const isValid = email.map(isValidEmail);
yield div([
    "The address is ", map((b) => b ? "valid" : "invalid", isValid)
  ]);

The isValid behavior is directly passed to the div, without the dynamic call. Is it correct?

dmitriz commented 7 years ago

Also wouldn't say no to some more details on the "mysterious" list function :)

https://github.com/funkia/turbine/blob/master/examples/counters/src/version3.ts#L66

paldepind commented 7 years ago

@dmitriz

That would remove the need for the model, right?

Yes, it actually would. But in the next version of Hareactive stepper will return either a Behavior<Behavior<A>> or a Now<Behavior<A>> so then you'd need the model.

The component itself looks like a general purpose selector component, to which you pass the array labels = [1, 2, 3, 4], along with the child component selectorButton.

I wonder if that can be made into something nice and reusable...

I think that is a good observation. It probably can be made into a completely reusable component.

Here it might be nice to slightly overload the div, so you could simply pass the stream or behavior of component directly to div:

https://github.com/funkia/turbine/blob/master/examples/counters/src/index.ts#L59

Yes. It should already be possible to do that. I don't know why a put an explicit dynamic in the code.

The isValid behavior is directly passed to the div, without the dynamic call. Is it correct?

Absolutely.

Also wouldn't say no to some more details on the "mysterious" list function :)

I'll update #53 with documentation for both lift and dynamic :smile:

dmitriz commented 7 years ago

@paldepind

That would remove the need for the model, right?

Yes, it actually would. But in the next version of Hareactive stepper will return either a Behavior<Behavior> or a Now<Behavior> so then you'd need the model.

I would also like to avoid the stepper :) I would add the memory behavior to the stream like in flyd as suggested here: https://github.com/funkia/hareactive/issues/29

It is really uniquely determined by the stream itself, so the structure is the same. And has the benefit of being more convenient to anyone using flyd and to cut down the number of methods and reduce the code complexity, I would think.

Any reasons against it?

dmitriz commented 7 years ago

The component itself looks like a general purpose selector component, to which you pass the array labels = [1, 2, 3, 4], along with the child component selectorButton. I wonder if that can be made into something nice and reusable...

I think that is a good observation. It probably can be made into a completely reusable component.

I'd be really interested in that. There are very few such truly reusable components out there, as far I can see. As @jayrbolton suggested, it should be decoupled from the markup as much as possible.

On the most abstract level you select an element in array, so basically its index. Every element in array should be a component outputting its own select stream. These can be merged together and completed to the memory behavior that is fed back to the selector.

On the outside, you pass it array of stateful components compArray, each component parametrized by whether it is selected (which can be just setting the active class but does not limit to it). Basically, the whole array depends on the selection value, so is really a function

compArray = (selectedIndex: Number): Array<Component>

that would be passed to the reusable Selector component as argument

const { selected } = yield Selector(compArray)

with the selected stream/behavior output as in the example.

What do you think?

dmitriz commented 7 years ago

Another more restrictive alternative would be the array of selected/unselected component pairs:

const arrayOfSelectableComponents: Array<(selected: Boolean): Component>

That is more focused to the common use case, where each component's state is its own selector.