React类组件箭头函数中JSX使用this.DemoRenderer报错问题咨询
在React 16.8.6版本的类组件中,用箭头函数定义的customerRender方法里,console.log能正常输出this.DemoRenderer函数,但返回<this.DemoRenderer />时会抛出错误:React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined。将该方法改为普通函数并在constructor中绑定this后,报错消失,但相同代码在在线编辑器中运行无报错,以下是问题原因分析:
错误代码示例
import React, {Component} from "react"; import ReactDOM from "react-dom"; class App extends Component { constructor(props) { super(props); this.DemoRenderer = function () { return <div>DemoRenderer</div>; }; } customerRender = () => { // 此处能正常打印this.DemoRenderer函数 console.log(this.DemoRenderer); // 但返回下方JSX会报错: // React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined return <this.DemoRenderer />; }; render() { return ( <div> hello {this.customerRender()} </div> ); } } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
无错误代码示例
class App extends Component { constructor(props) { super(props); this.DemoRenderer = function () { return <div>DemoRenderer</div>; }; // 绑定this到customerRender this.customerRender = this.customerRender.bind(this); } customerRender() { return <this.DemoRenderer />; }; // ... 其余render方法同上 }
项目依赖配置
"dependencies": { "react": "16.8.6", "react-dom": "16.8.6", "react-scripts": "3.0.1" }, "devDependencies": { "typescript": "3.3.3" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" },
问题原因分析
- JSX编译阶段的this指向差异
JSX会被Babel编译为React.createElement调用,对于<this.DemoRenderer />这种写法,编译时会优先解析this的上下文。箭头函数作为类字段(customerRender = () => {})的初始化顺序在constructor之后,但旧版本Babel编译类内部JSX时,会将this.DemoRenderer错误解析为类的静态属性而非实例属性——因为箭头函数类字段的作用域处理逻辑和普通类方法不同,导致编译阶段无法识别实例上的DemoRenderer,运行时自然返回undefined。
而普通类方法在constructor中绑定this后,作为原型方法,其内部JSX编译时会保留对实例this的引用,运行时能正确访问到实例上的DemoRenderer函数。
本地与在线环境的编译配置差异
在线编辑器使用的Babel版本或配置更完善,对类字段和JSX的作用域处理做了优化,能够正确识别实例属性,因此相同代码不会报错。而本地环境使用的react-scripts 3.0.1对应的Babel版本较旧,存在这个编译逻辑的缺陷。临时解决方案验证
如果把this.DemoRenderer赋值给箭头函数内部的局部变量,再用变量作为组件,就能绕过编译阶段的错误解析:
customerRender = () => { const Renderer = this.DemoRenderer; return <Renderer />; };
这种写法让JSX编译时直接引用局部变量,跳过对this的静态解析,运行时就能正确获取到实例方法。
内容的提问来源于stack exchange,提问作者Terence Cheng

