dyo / dyo

Dyo is a JavaScript library for building user interfaces.

Home Page:https://dyo.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SVG rendering by generators (or array) is broken (namespace context information not propagating)

thephoenixofthevoid opened this issue · comments

The following code:

function *MyGenerator({ start = 0, end = 20 }) {
  for (let i = start; i < end; i++) {
    yield <path d={`M 0 ${5*i} h 100`} stroke="black" />
  }
}

function Example2() {
  return <svg>{h(MyGenerator, { start: 0, end: 20 })}</svg>
}

render(<Example2/>, document.body);

results in blank window, but elements are visible in Chrome Inspector.

But any path element has incorrect namespaceURI:

**>** temp1
**<** <path d="M 0 20 h 100" stroke="black"></path>
**>** temp1.namespaceURI
**<** "http://www.w3.org/1999/xhtml"

At the same time this code:

function *MyGenerator({ start = 0, end = 20 }) {
  for (let i = start; i < end; i++) {
    yield  <svg>
      <path d={`M 0 ${5*i} h 100`} stroke="black" />
    </svg>
  }
}

function Example2() {
  return <svg>{h(MyGenerator, { start: 0, end: 20 })}</svg>
}

render(<Example2/>, document.body);

works as expected (from visual prospective, ignoring nesting svg tags in the top level svg) and any path element has correct namespaceURI:

**>** temp1
**<** <path d="M 0 20 h 100" stroke="black"></path>
**>** temp1.namespaceURI
**<** "http://www.w3.org/2000/svg"

And finally, this code:

function MyNotGenerator({ start = 0, end = 20 }) {
  return <path key={start} d={`M 0 ${5*start} h 100`} stroke="black" />
}

function Example3() {
  return <svg>{h(MyNotGenerator, { start: 0, end: 20 })}</svg>
}

render(<Example3/>, document.body);

works as well.

Everything looks like propagating of namespaceURI context data is broken for iterables (arrays as well - not only generators).

@thephoenixofthevoid

Independent of the SVG related bug here, just a few words regarding the use of generator functions in Dyo/React/Whatever.

I don't think that it is a good idea to use generator functions as Dyo components or generators as children in general.
If you try this in React you'll get the following warning (in DEV mode):

Warning: Using Generators as children is unsupported and will likely yield unexpected results because enumerating a generator mutates it. You may convert it to an array with Array.from() or the [...spread] operator before rendering. Keep in mind you might need to polyfill these features for older browsers.

ECMAScript generators behave a bit odd sometimes - that's why they cause some trouble and are often not supported in React-like libraries as children:

function* generate() {
  yield 1
  yield 2
  yield 3
}

const arr = [1, 2, 3]
const itr = generate()

itr[Symbol.toStringTag] // -> 'Generator' - just for information
arr[Symbol.iterator]() === arr[Symbol.iterator]() // -> false - as most may expect
itr[Symbol.iterator]() === itr[Symbol.iterator]() // -> true - as most may NOT expect

See also this example:

function* generate() {
  yield 1
  yield 2
  yield 3
}

const itr = generate()

console.log('First round:')
for (const value of itr) console.log(value)
console.log('Second round:')
for (const value of itr) console.log(value)

Output will be:

First round:
1
2
3
Second round:

and NOT (as most would expect):

First round:
1
2
3
Second round:
1
2
3

@mcjazzyfunky I don't think that would be an issue with *generators in Dyo as the iterator generator will re-generate and iterator at each segment. that is before the second round for example you, create a new const itr = generate().

@thysultan @thephoenixofthevoid
I do not doubt that generator function components are working properly in Dyo.
I just doubt that it's a good idea.
Just in the moment I've checked the official Dyo and yes using generator functions as components is still an official Dyo feature (https://dyo.js.org/component.html#generator) - actually I've mistakenly thought this is not a supported feature in later Dyo versions any longer.

So @thephoenixofthevoid: My bad, I was wrong, generator function components are indeed an official supported feature in Dyo. So please ignore my comment above and sorry for wasting your time.

@thysultan: Nevertheless, I'm really very strongly of the opinon that generator function components and generators as children in general are big troublemakers and should not be supported in Dyo (for example if you add some DEV system key validation sometime in future => this was one of the reasons why in React the obove written warning was added).
But I will open a separate issue for that topic soon, no need to discuss it here.

Actually there are use cases that seem to be hard to implement if not using generators. A few I am experimenting now involves a generator that actually never ends. Anyway, this bug affects arrays as well. By the way, it would be useful to somehow expose providing namespace of an element to the surface API. Autodetecting right namespace could make use of this API as well, because for now it's the hardest to figure out what's going on part of source code.

@thysultan: Nevertheless, I'm really very strongly of the opinon that generator function components and generators as children in general are big troublemakers and should not be supported in Dyo (for example if you add some DEV system key validation sometime in future => this was one of the reasons why in React the obove written warning was added).
But I will open a separate issue for that topic soon, no need to discuss it here.

I have to highlight the fact that you are talking about using iterators as an element, but here the key feature is that the generator function (that returns iterator every time it's called) are component. And you have to create an element of it before you can pass it anywhere. You don't have problems with react instantiating classes for you, then why would you have problems with instantiating iterators? I can always create a class component in React and make it so it would iterate and append children gradually, but a lot of user code has to be written. I consider this library to be one or two levels higher than react. React simply can no longer move fast, just to break things many people are counting on.

@thephoenixofthevoid Thanks for your feedback. I'll answer at issue #127 if you do not mind. Like said, this issue here is about a bug regarding SVG, so I do not want to pollute it with some discussion about some other topic.