question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Handling lists in Cycle.js

See original GitHub issue

Handling lists in Cycle is hard. It’s the only sad thing about Cycle in my opinion so far, specially because lists are so common. Otherwise, Cycle is beautiful. Because it keeps on popping up so often, let’s take it a bit more seriously. This issue is to track progress being done to update docs (cycle.js.org), Nick’s library Cycle Collections, and other initiatives that may help people feel comfortable building lists in Cycle.js.

There are 4 solutions, here are their pros & cons:

  1. Manually build the dataflow, which will contain circular dependencies. This is what we do e.g. in TodoMVC.
    • Pros: explicit, no magic; follows Cycle.js principles of dataflow and purity; is being improved if people use xstream, it’s easier to do that in xstream than it is with RxJS.
    • Cons: hard to understand and be comfortable with; probably a bit verbose.
  2. Wrap the Cycle.js subapps as Web Components https://github.com/staltz/cycle-custom-elementify
    • Pros: easier for most web developers to understand; explicit, no magic; enables Cycle.js subapps to be used outside Cycle.js;
    • Cons: subapp cannot have effects besides DOM-related; Diversity-support is annoying; Web Components spec is still in flux or not official yet.
  3. Global state at the top-most component (main).
    • Pros: a bit simpler and familiar mental model (like Redux); still aligned with Cycle.js principles of dataflow and purity.
    • Cons: still some circular dependency machinery to set up; not fractal, but if you know the tradeoffs, this may not be a problem at all.
  4. Stanga and similars.
    • Pros: Like the above, but circular dep machinery is hidden and automatically managed; is fractal; lenses API as a plus.
    • Cons: not aligned with Cycle.js principles of dataflow and purity with regard to drivers, harder to reason about what should be in a driver and what should not be.
  5. Cycle Collections, the library Nick is working on.
    • Pros: aligned with Cycle.js principles, easier to understand the API and reuse, not so much boilerplate/verbosity.
    • Cons: “magic”, you give it X and Y and “things just work”.
  6. Cycle Onionify, https://github.com/staltz/cycle-onionify
    • Pros: fractal with “lenses/cursors”-like API, only one state tree, hides away both fold and imitate, removes props vs state dichotomy.
    • Cons: currently only xstream support. No props vs state may lead to undesireable concurrent state modifications between parent and children.

CC @Widdershin @laszlokorte @milankinen @TylorS

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:17
  • Comments:58 (38 by maintainers)

github_iconTop GitHub Comments

8reactions
maiermiccommented, Oct 30, 2016

@all I try to describe this issue in the following. Please give feedback to improve it.

This issue deals with the question how to create dynamic list components.

Issue description

A dynamic list component is a component that consists of a dynamic number of child components (of same kind) in a specific order.

Changes

List of child components is dynamic and may change:

  • create/add (new) child
  • remove child
  • change order of children
  • change of child state may cause change of list component state

Communication

Components exchange data (state, events, actions) via streams (sources and sinks). Those streams have to be connected appropriately. Communication appears between:

  • child -> parent
  • parent -> child
  • parent -> children
  • child -> parent -> grandparent
  • grandparent -> parent -> child
  • child -> child (siblings)

or in short:

  • grandparent <-> parent <-> child(ren)

Difficulties

  • identify/distinguish children
  • share state between parent and children
  • circular dependency (parent -> child -> parent)
  • connecting dynamic number of sources and sinks
  • forward child sinks (side effects) to grandparent

Example

TodoMVC is a popular example of this use case.

Features

  • text field to add new child to list
  • show children
    • all
    • only active
    • only completed
  • show count of active children
  • show count of completed children
  • clear completed children
  • delete child
  • edit child task description
  • change active state of all shown children

Screenshot

todomvc

Note: You might count other elements (input field at the top, label and buttons at the bottom) among parent. However, parent can also be a plain list and its grandparent adds other elements (to control it). I leave this design decision open. The screenshot shows what belongs at least to parent (list component).

Changes

  • create/add (new) child
  • show filtered children (active/completed)
  • delete child
  • clear completed children (delete children based on their active state)
  • edit child task description
  • change of child’s active state might causes change of shown children (if list is filtered) and might lead to a state change of parent
  • change active state of all shown children

Note: change order of children is not a feature of common TodoMVC, but an obvious example would be a button to sort items.

Communication

Components exchange data (state, events, actions) via streams (sources and sinks). Those streams have to be connected appropriately. Communication appears between:

  • child -> parent
    • child tells parent to remove it (child)
  • parent -> child
    • change active state
  • child -> parent -> grandparent
    • in a bottom-up approach you might expose child/parent state to grandparent (for example (to calculate) count of active/completed children)
  • grandparent -> parent -> child
    • change active state of all shown children is triggered by parent or grandparent (depends on design decision, see screenshot note above)

No child -> child (siblings) communication in this example.

Difficulties

  • identify/distinguish children
    • delete child: which child component should be deleted?
    • edit child: which child component should be edited?
    • change active state of child: which child?
  • share state between parent and children
    • parent filters children based on their state (active/completed)
    • parent deletes children based on their state (completed)
  • circular dependency (parent -> child -> parent)
    • parent creates children and needs a stream that indicates when to delete a child, but child sink (delete child) is part of this stream
  • connecting dynamic number of sources and sinks
    • how do we get DOM/vtree of children
  • forward child sinks (side effects) to grandparent
    • in a bottom-up approach, you can consider combination of children’s DOM sources as parent DOM source (that is passed to the grandparent) to be an example
    • if child components would have other side effects (for example HTTP requests) then those child sinks have to be combined in a similar way
4reactions
Hypnosphicommented, Nov 13, 2016

I think there still one option missing here: not to use isolated components for list items at all, and handle all the actions/reducer/state in the list component. Here’s basic todo app implemented with this approach: https://esnextb.in/?gist=f5bac3760fa1730e69ff463f5e428fa9

Off course, this may be not applicable when children are really complex and need to hold its own state, but quite often that’s not the case. There’s an opinion that anytime you have a dynamic list of anything in cycle app, you need some solution for handling circular dependencies, but it’s not really true.

This differs from “global state” option: the state isn’t global, it’s private to the list.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Loop through an array in JavaScript - Stack Overflow
One advantage of this approach is that you can choose how to handle sparse arrays. The above code will run the body of...
Read more >
Loops and iteration - JavaScript - MDN Web Docs
It then iterates over all the object's properties and returns a string that lists the property names and their values. function dumpProps(obj, ...
Read more >
How to Loop Through an Array in JavaScript – JS Iterate Tutorial
The array method forEach() loop's through any array, executing a provided function once for each array element in ascending index order. This ...
Read more >
We have some JavaScript code that will cycle over list items ...
We have some JavaScript code that will cycle over list items and apply colors from an array called colors. The code will apply...
Read more >
How to loop through objects in JavaScript? - Flexiple
This data can come in the form of arrays, lists, maps or other objects. In this article we will deal with this problem...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found