You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改JSX大括号对对象/类实例的求值逻辑?

问题分析

你的T类继承了Function,导致实例a是一个函数对象。当React在JSX大括号中处理函数类型的值时,会默认将其视为React组件进行渲染,而非直接转换为字符串——这就是{a}输出<div>...</div>的核心原因,而${a}会触发toString(),a()会触发代理的apply逻辑,因此这两种情况能得到预期结果。

解决方案

以下几种方案均可实现目标,且无需修改JSX语法:

方案1:实现Symbol.toPrimitive钩子

利用JS原生的类型转换符号,强制React在处理对象时返回预期的字符串值:

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();
  }
  // 添加类型转换钩子
  [Symbol.toPrimitive](hint) {
    // 当需要字符串转换时返回bar()结果
    if (hint === 'string' || hint === 'default') {
      return this.bar();
    }
    // 其他情况默认处理
    return super[Symbol.toPrimitive]?.(hint);
  }
}

const a = new T('foo');

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

console.log(jsxToString(el1)) // "<div>foobar</div>"
console.log(jsxToString(el2)) // "<div>foobar</div>"
console.log(jsxToString(el3)) // "<div>foobar</div>"

方案2:改为普通类+Proxy实现可调用

放弃继承Function,用普通类配合Proxy让实例可调用。此时a不再是函数对象,React会自动调用其toString()方法:

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

// 改为普通类,不继承Function
class T {
  foo;
  constructor(foo) {
    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)) // "<div>foobar</div>"
console.log(jsxToString(el2)) // "<div>foobar</div>"
console.log(jsxToString(el3)) // "<div>foobar</div>"

方案3:让函数实例作为组件返回文本

如果必须继承Function,可以让实例被当作React组件调用时直接返回目标字符串(React 16+支持组件返回原生字符串/数字):

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)) // "<div>foobar</div>"
console.log(jsxToString(el2)) // "<div>foobar</div>"
console.log(jsxToString(el3)) // "<div>foobar</div>"

内容的提问来源于stack exchange,提问作者Jesus_21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 22:12:30