英文:
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 "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 e.g. make `a` be a React element,
which can also be called as a function, and you'd need to overwrite it's
`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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论