改变JSX大括号如何评估对象/类实例。

huangapple go评论66阅读模式
英文:

Change how JSX curly braces evaluates an Object/Class Instance

问题

我有以下代码片段:

import React from 'https://esm.sh/react@18.2.0'
import jsxToString from "https://cdn.skypack.dev/jsx-to-string@1.4.0";

class T extends Function {
  foo;
  constructor(foo) {
    super();
    this.foo = foo;
    
    return new Proxy(this, {
      apply: (target) => target._call()
    });
  }
  bar() {
    return this.foo + 'bar';
  }
  toString() {
    return this.bar();
  }
  _call() {
    return this.bar();
  }
}

const a = new T('foo');

const el1 = (<div>{`${a}`}</div>);
const el2 = (<div>{a()}</div>);
const el3 = (<div>{a}</div>);

console.log(jsxToString(el1))
console.log(jsxToString(el2))
console.log(jsxToString(el3))

输出如下:

"<div>foobar</div>"
"<div>foobar</div>"
"<div>...</div>"

我知道这很奇怪,但长话短说,我需要能够以相同的方式表示我的a对象,无论我如何通过JSX大括号传递它。

{`${a}`} => 调用 toString OK
{a()} => 调用 _call OK
{a} => KO,我怀疑这种语法会像eval(a)一样执行,因此最终失败。

是否有一种方法可以强制指定通过JSX大括号传递对象时的求值方式?
我对任何建议都持开放态度,我不关心性能或其他任何内容,可以将其视为概念验证。

唯一的要求是我不能更改JSX语法。

英文:

I have the following snippet of code:

import React from 'https://esm.sh/react@18.2.0'
import jsxToString from "https://cdn.skypack.dev/jsx-to-string@1.4.0";

class T extends Function {
  foo;
  constructor(foo) {
    super();
    this.foo = foo;
    
    return new Proxy(this, {
      apply: (target) => target._call()
    });
  }
  bar() {
    return this.foo + 'bar';
  }
  toString() {
    return this.bar();
  }
  _call() {
    return this.bar();
  }
}

const a = new T('foo');

const el1 = (<div>{`${a}`}</div>);
const el2 = (<div>{a()}</div>);
const el3 = (<div>{a}</div>);

console.log(jsxToString(el1))
console.log(jsxToString(el2))
console.log(jsxToString(el3))

The output is the following:

"<div>foobar</div>"
"<div>foobar</div>"
"<div>...</div>"

I know this is weird but long story short, I need to be able to represent my a object the same way however I pass it through JSX curly braces.

{`${a}`} => calls toString OK
{a()} => calls _call OK
{a} => KO, I suspect that this syntax does something like eval(a) so it end up failing.

Is there a way to force how an object is evaluated when passed through JSX curly braces?
I am open to any suggestion, I don't care about performance or anything, think of it as a proof of concept.

The only requirement is that I can't change the JSX syntax.

答案1

得分: 1

I think this is not possible.

There are no "instance getters" in JavaScript. I.e. you can write getters for properties, but not for the object itself.

JSX evaluation

The code between the curly braces in JSX is just normal JavaScript code (i.e. no eval() is happening or something).
Your JSX code will be converted to plain JavaScript:
```const el1 = React.createElement("div", null, ${a});
const el2 = React.createElement("div", null, a());
const el3 = React.createElement("div", null, a);


### React elements

The [3rd parameter of createElement](https://beta.reactjs.org/reference/react/createElement#parameters) is expected to be a React node, i.e. a React element, string, number, and some others.

So you would need to, for example, make `a` be a React element, which can also be called as a function, and you'd need to overwrite its `toString` method, but React elements are not extensible, so that is no option.

In fact, [React states this explicitly][1]:
> You must treat React elements and their props as immutable and never change their contents after creation.

[1]: https://react.dev/reference/react/createElement#caveats

<details>
<summary>英文:</summary>

I think this is not possible.

There are no &quot;instance getters&quot; in javascript. I.e. you can write getters for properties,
but not for the object itself.

### JSX evaluation

The code between the curly braces in JSX is just normal javascript code
(i.e. no `eval()` is happening or something).
Your JSX code will be converted to plain javascript:

const el1 = React.createElement( "div", null, ${a} );
const el2 = React.createElement( "div", null, a() );
const el3 = React.createElement( "div", null, a );


### React elements

The [3rd parameter of createElement](https://beta.reactjs.org/reference/react/createElement#parameters) is
expected to be a React node, i.e. a React element, string, number and some others.

So you would need to e.g. make `a` be a React element,
which can also be called as a function, and you&#39;d need to overwrite it&#39;s
`toString` method, but React elements are not extensible, so that is no option.

In fact, [React states this explicitly][1]: 
&gt; You must treat React elements and their props as immutable and never
&gt; change their contents after creation


  [1]: https://react.dev/reference/react/createElement#caveats

</details>



huangapple
  • 本文由 发表于 2023年3月3日 21:16:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75627568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定