calmm-js / karet Goto Github PK
View Code? Open in Web Editor NEWKaret is a library that allows you to embed Kefir observables into React VDOM
License: MIT License
Karet is a library that allows you to embed Kefir observables into React VDOM
License: MIT License
Currently one needs to write, e.g:
<span dangerouslySetInnerHTML={U.template({ __html: obs })} />
It would be nice to be able say just:
<span dangerouslySetInnerHTML={{ __html: obs }} />
cc @rikutiira
The current implementation calls forceUpdate
during initial mounting if all the observables produce values synchronously. The call causes no problems with React, but Preact doesn't like that. The call to forceUpdate
is unnecessary and could be considered a bug that should be fixed (even before 2.0.0).
Karet currently only replaces the React.createElement
function. If you use React.cloneElement
to clone an element without observables in such a way that the new clone has observables in it, then the resulting element currently will not be lifted.
I've been playing around with some of Karet's ideas in a library of my own, but one of the things I'm struggling with is an idiomatic way to respond to componentDidUpdate
with observables.
In my specific example, I want to run a syntax highlighter over a code
element after the element's text has been updated, but because the FromClass
component returned by createElement
never appears in "userland", there's no good way to respond to React's lifecycle methods without dropping down into a "plain" React component, which isn't a terrible solution but something I was hoping to avoid.
Is this something you've run into? How have you solved it?
React allows children to be an arbitrarily nested array. Karet currently doesn't. This should be fixed.
I know this library is specially modelled for Kefir streams, hence its name, but I think it would be great if any reactive streams library could be used (I personally like https://github.com/staltz/xstream, although Kefir looks great for my use-case), maybe using a different name and a different repository.
I've come up with the following changes: master...fiatjaf:b460d77fa8b38188e8003dc3de90bf161dc89d67
But they don't pass the tests (I've used xstream on the tests instead of Kefir), so I'm looking for help.
https://codesandbox.io/s/yw63o1zr1x
Here's an example case where you need to explicitly use <React.Fragment>
to wrap children
inside <Provider>
because one of the children is an observable (due to U.when(obs, value)
).
It'd be preferable if karet's Provider would work out of the box with observable children.
Another thing here is that for some reason React is warning about missing keys when using children inside the React.Fragment. I think there has been issues with same thing previously but those were fixed?
Even now, Karet essentially just works with Preact in addition to React. Karet only uses createElement
and Component
and assumes that Component
s support (componentWillReceiveProps
(is not strictly required),) componentWillMount
, componentWillUnmount
, render
and forceUpdate
methods (React setState
is not used). It would be nice to make Karet directly configurable or parameterized with respect to the VDOM library. Suggestions on how to best expose such configurabilty or parameterization are welcome!
Hi.
I decided to help build a port of this library to rxjs so it is also available for projects that rely on Rx as their FRP library.
So far I have managed to port most of the functionality but I am still 2 test cases away from succeeding.
One scenario is when a single react node has more than 1 Observable embedded.
The other is that the child context test does not render.
Any help or suggestion is greatly appreciated. I have been following this project for a while and I would like to contribute in the best way I can.
Thanks in advanced
This is the source code:
https://github.com/MarcCloud/xaret/blob/master/src/xaret.js
I'm puzzled by the magic that seems to be happening here (also, it's not working in my case, so it means I've misunderstood everything).
Reading the source didn't work. I can't wrap my mind around the fact that a function may know beforehand that a variable will be used on its body then automatically call a function on that variable.
Today if you write a templated string like
`my count is ${Kefir.sequentially(1000, [1, 2, 3, 4, 5])}`
karet
will not know there's an observable inside the string and will print my count is [sequentially]
instead.
If there was a helper function k
, for example, for passing template strings to, that could identify which of the template strings' variables were observers and treat them like a children. Basically just turning a template string inside a React children as multiple different children would make this work, so instead you would have to write
k`my count is ${Kefir.sequentially(1000, [1, 2, 3, 4, 5])}`
And that's it.
What do you think? Should I submit a PR? What do you think would be the best way to implement such a feature?
React 17 has introduced support for a new JSX transform.
The old JSX transform would do the following:
import React from 'react';
function App() {
return <h1>Hello World</h1>;
}
code is transformed into:
import React from 'react';
function App() {
return React.createElement('h1', null, 'Hello world');
}
The new JSX transform would do the following:
function App() {
return <h1>Hello World</h1>;
}
code is transformed into:
// Inserted by a compiler (don't import it yourself!)
import {jsx as _jsx} from 'react/jsx-runtime';
function App() {
return _jsx('h1', { children: 'Hello world' });
}
Current version of Karet does not pass through the proposed React Hooks that are available in 16.7.0-alpha.0
. React Hooks do seem to work fine with Karet, e.g. using useContext
. It would be useful to "support" React Hooks by passing through the exports like is done for a number of other React exports.
^16.7.0-alpha.0
in the branch.^4.1.0-alpha.0
, with the new exports.I'm working on a framework of my own, borrowing some ideas from karet, and I'm struggling with iterated lists, specifically the key
attribute. What I'd like to be able to do is structure a list something like this:
const TodoList = ({ props$ }) => (
<div>
<h2>My Todos</h2>
{props$.map(todos => todos.map(todo => (
<TodoItem props$={/* how do i get a stream representing an individual todo? */}
key={todo.id} />
)))}
</div>
)
As the comment suggests, I'd like to provide the child component a stream representing the current state of the individual list item, but I'm not seeing a good way to structure the todos
object that doesn't end up requiring a lot of iteration to create a stream of todo instances.
Based on the documentation, it appears you're mostly using the array indicies with lenses to decompose (? is this the right word?) the central Atom into into individual streams for each instance. The problem I'm having with that is using the array index as the key
is a React anti-pattern. While the linked post suggests it could produce strange or broken results if you add or remove elements from the array, in my use case, it would also prevent the VDOM implementation from rearranging the currently existing DOM nodes and produce node updates instead. Let me explain:
If we have a list that looks like this:
<h1>My Favorite View Libraries</h1>
<ol>
<li>React</li>
<li>karet</li>
<li>Vue.js</li>
</ol>
And we decide to move karet to the first spot to make it look like this:
<h1>My Favorite View Libraries</h1>
<ol>
<li>karet</li>
<li>React</li>
<li>Vue.js</li>
</ol>
using array indexes would produce 2 text node changes, rather than rearranging the current DOM. This is inefficient, as a single move would be better than 2 text changes, and it denies us the ability to animate the DOM movement, as the DOM node doesn't actually change position.
I've played around with karet and I love the idea of being able to embed observables into the VDOM like that, and I'm trying to take it a bit further, such that all possible interactions in the DOM are expressed as embedded Observables, including DOM attributes & events, but I'm struggling with the API design around children, and I'm wondering how you solve this with karet / kefir.atom.
My current thought is to require something like this:
const TodoList = ({ props$ }) => (
<div>
<h2>My Todos</h2>
{props$.map(todos => todos.order.map(key => (
<TodoItem props$={props$.map(todos => todos.dict[key])}
key={key} />
)))}
</div>
)
Where todos
looks like this:
const todos = {
order: ['a', 'c', 'b'],
dict: {
a: todo1,
b: todo2,
c: todo3
}
}
Is this a pattern you've used before with karet? Do you have any insight / suggestions for this API design?
Thanks for your time!
The idea originally with Karet was to setup the exports so that one could just import from 'karet'
instead of 'react'
. IOW, so that the exports would be identical except that the Karet versions would support observables. While it is possible to make it so, the current hack is just incorrect and fixing it seems like waste, because it would require duplicating the React exports manually (and possibly matching them version by version).
What I mainly want is to be able to just import from 'karet'
to make the default Babel JSX transform use createElement
from Karet instead of React. This way one can conveniently decide, module by module, whether one uses Karet or plain React. In order to achieve that, Karet only needs to have a named export for createElement
and one can then import * as React from 'karet'
.
Changing the exports of Karet is a breaking change. The basic fix is fairly simple:
- import React from 'karet'
+ import * as React from 'karet'
Dropping the hacky default export means that dead code elimination will potentially work better (when React does it properly—currently it doesn't). Karet would only export createElement
, fromKefir
, and fromClass
.
Also, if you are using named exports from React (the real React), you will then need to import those from the real 'react'
. E.g.
import {Component} from 'react'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.