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

Filtering atoms in todo example #45

Open
merisbahti opened this issue Nov 28, 2020 · 3 comments
Open

Filtering atoms in todo example #45

merisbahti opened this issue Nov 28, 2020 · 3 comments

Comments

@merisbahti
Copy link

merisbahti commented Nov 28, 2020

Hello!

I was recently made aware of this library, and I felt really amazed, it feels like someone is thinking like me out there.

I've made a similar library, inspired by jotai and uses optics-ts, but specifically for react, called klyva.

I have a very similar example to you, where I implement todo-application, and I was recently struggling with implementing filter.

Please note that, in klyva, to get Array<Atom<Element>> from an Atom<Array<Element>>, one uses a function called useAtomSlice. This is very similar, I believe, to what ListView accomplishes (both even make them removable):

So what I did, was implement a value, which represents if the atom at index should be filtered. Its name is shouldBeFilteredAtIndex.
Given shouldBeFilteredAtIndex, one can filter the Array<Atom<...>> here before rendering them out.

How would you go about implementing "filter" of atoms, using ListView component? I see no way to filter it based on its value.

@merisbahti
Copy link
Author

merisbahti commented Nov 28, 2020

What I tried the first time, was to use optics-ts filter-optic, but it didn't work out that good - related discussion here.

Another idea, would be to create an atom which represents the same thing (shouldBeFilteredAtIndex) but return null in the render-prop in ListView if that specific todo should be filtered away.

I guess I'm wondering, what do you feel is more idiomatic? Is there a good optics, or view based approach?

@raimohanska
Copy link
Owner

I come with an FRP background so for me, filtering an Atom would mean skipping a value that doesn't match a predicate. So, from the user's point of view it means that the Atom should "freeze" to its previous value (the last one that matched the predicate). In the Lonna FRP library used in Harmaja, you can filter atoms, as seen in this test. This sort of filtering is employed in the Harmaja ListView to ensure that item views are not rendered after the particular item has been removed from the list atom.

Then again, you seem to want to filter out unwanted values from an atom that holds an array of values, that's of course a map or view on the Atom, where you apply a filter to the contained array. This combined with the "remove" operation seems to cause problems with atoms+lenses (as you discovered with @akheron ). I'm not super deep into optics myself and cannot solve that problem for you.

With Harmaja, you can pick wither Atoms+Lenses or Actions+Reducer and for some cases, actions+reducer feel more suitable. When using actions+reducer, you don't have to solve that complex problem but can compose your UI from view components that don't have to worry about how mutations are implemented - just dispatch actions for the reducer. Or you can also combine the two approaches to get the best of both worlds.

And these solutions are not really Harmaja-specific, you could very well pick the Lonna library for Atoms and all other FRP constructs (event streams, properties, buses...) and write a few React hooks to use them with React.

@akheron
Copy link
Collaborator

akheron commented Nov 29, 2020

Oh, sorry @merisbahti. When we discussed in the optics-ts issue I didn't pay attention to what the actual problem was you were trying to solve 🙄

I've built something similar to calmm.js in TypeScript here: https://codesandbox.io/s/goofy-sun-j1zoz. Have a look at src/atom.ts. Near the end it has the function mapElems which does what I think want to accomplish.

It basically uses the .index() prism (alias of .at()) of optics-ts to focus on an element of an array. This prism is removable, so you can just call O.remove on it, and it's wrapped to a RemovableAtom that allows doing just this.

If a prism stops matching, e.g. when the prism focuses on the last element of an array and something is removed from the array, the corresponding atom is "deactivated", i.e. it stops subscribing to its parent.

The mapElems function is almost 1:1 copy-paste from karet.util here (part of calmm.js). karet.util also has the function mapElemsWithId which allows using React's key to reorder elements without re-rendering. I think I also implemented it at some point for my TypeScript project, but it seems to be missing from the codesandbox. Harmaja's ListView does the same thing as mapElemsWithId, although it has to do a bit more because there's no React to help reordering nodes based on key.

Dunno if this stuff helps you, but I hope you get some ideas at least!

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

3 participants