"react-hot-loader/babel" 破坏了我的构建——为什么需要它?
"react-hot-loader/babel" breaks my build -- why is it needed?
一旦我将 "react-hot-loader/babel"
添加到我的 .babelrc
,它就会破坏我的 React 组件。
具体来说,我有一些代码如下所示:
export default class Editor extends React.Component {
componentDidMount() {
console.log('this.canvas',this.canvas);
// ...
}
setRef = node => {
console.log('setRef');
this.canvas = node;
}
render() {
// tabIndex is needed to receive keyboard events --
return <canvas className={this.props.className} ref={this.setRef} tabIndex={0} />;
}
}
当我 运行 它时,我在我的 Chrome 开发工具中看到了这个:
setRef
this.canvas undefined
这很奇怪,因为我们可以看到它在 调用 componentDidMount
之前设置 this.canvas
所以我不知道 react-hot-loader/babel
正在努力打破它。
没有 react-hot-loader/babel
,一切正常,包括热重载。
所以,我的问题是:
- "react-hot-loader/babel"实际上是做什么的?
- 如何才能不破坏我的class属性?
这是 React 16.1、react-hot-loader 3、webpack 3.11、babel 6.x
我的 .babelrc
如果你想看:
{
"plugins": [
"transform-object-rest-spread",
"syntax-jsx",
"transform-react-jsx",
"transform-react-display-name",
"transform-class-properties",
"transform-function-bind",
"transform-decorators-legacy"
],
"compact": false,
"env": {
"development": {
"plugins": [
"transform-react-jsx-self",
"transform-react-jsx-source",
[
"styled-components",
{
"displayName": true,
"minify": false
}
]
//
//"react-hot-loader/babel"
],
"presets": [
[
"env",
{
"targets": {
"browsers": "last 2 chrome versions"
},
"modules": false
}
]
],
},
"webpack": {
"presets": [
[
"env",
{
"targets": {
"node": "current"
},
"modules": "commonjs"
}
]
]
}
}
}
这似乎是 react-hot-loader v4.
中的 bug in react-hot-loader v3 (I was able to reproduce the issue) and it is fixed
根据 this comment,此问题似乎是由 react-proxy 中的代理逻辑引起的。一个技巧是存储一个对象来保存你的引用,这将被 react-proxy 复制到代理,并将在 this
:
的代理版本中可用
export default class App extends React.Component {
constructor(props) {
super(props);
this.myRefs = {};
this.setRef = this.setRef.bind(this);
}
componentDidMount() {
console.log('componentDidMount',this.myRefs.div); // <-- Not null!
}
setRef(node) {
this.myRefs.div = node;
console.log('setRef',this.myRefs.div);
};
render() {
return <div ref={this.setRef}>test</div>
}
}
或者如 next comment 中所述,确保您的函数绑定在 componentWillMount
:
中完成
export default class App extends React.Component {
constructor(props) {
super(props);
// Do not bind here, "this" will get proxied.
}
// Proxy "this" is now available. Bind here.
componentWillMount() {
this.setRef = this.setRef.bind(this)
}
componentDidMount() {
console.log('componentDidMount',this.div); // <-- Not null!
}
setRef(node) {
this.div = node;
console.log('setRef',this.div);
};
render() {
return <div ref={this.setRef}>test</div>
}
}
我确实用 react-hot-loader v4 验证了有问题的代码,它已修复。
PS: 使用答案作为注释,因为我需要格式化
我能够重现该问题。出现此问题是因为热重新加载程序将代码更改为
setRef = (...params) => this.__setRef__REACT_HOT_LOADER__(...params)
然后在组件prototype
中
__setRef__REACT_HOT_LOADER__(node) {
console.log("setRef called", this, node);
if (this === null) return;
if (node === null) return;
console.log(node);
this.div = node;
}
我认为这打破了 this
链或者这个副本变得不同。有两个变化将起作用
componentDidMount = () => {
console.log('componentDidMount',this.div);
}
如果你使用上面的方法就可以了,因为 get same this then。或者您需要将 setRef 更改为 lambda
return <div ref={ node => this.div=node }>test</div>
一旦我将 "react-hot-loader/babel"
添加到我的 .babelrc
,它就会破坏我的 React 组件。
具体来说,我有一些代码如下所示:
export default class Editor extends React.Component {
componentDidMount() {
console.log('this.canvas',this.canvas);
// ...
}
setRef = node => {
console.log('setRef');
this.canvas = node;
}
render() {
// tabIndex is needed to receive keyboard events --
return <canvas className={this.props.className} ref={this.setRef} tabIndex={0} />;
}
}
当我 运行 它时,我在我的 Chrome 开发工具中看到了这个:
setRef
this.canvas undefined
这很奇怪,因为我们可以看到它在 调用 componentDidMount
之前设置 this.canvas
所以我不知道 react-hot-loader/babel
正在努力打破它。
没有 react-hot-loader/babel
,一切正常,包括热重载。
所以,我的问题是:
- "react-hot-loader/babel"实际上是做什么的?
- 如何才能不破坏我的class属性?
这是 React 16.1、react-hot-loader 3、webpack 3.11、babel 6.x
我的 .babelrc
如果你想看:
{
"plugins": [
"transform-object-rest-spread",
"syntax-jsx",
"transform-react-jsx",
"transform-react-display-name",
"transform-class-properties",
"transform-function-bind",
"transform-decorators-legacy"
],
"compact": false,
"env": {
"development": {
"plugins": [
"transform-react-jsx-self",
"transform-react-jsx-source",
[
"styled-components",
{
"displayName": true,
"minify": false
}
]
//
//"react-hot-loader/babel"
],
"presets": [
[
"env",
{
"targets": {
"browsers": "last 2 chrome versions"
},
"modules": false
}
]
],
},
"webpack": {
"presets": [
[
"env",
{
"targets": {
"node": "current"
},
"modules": "commonjs"
}
]
]
}
}
}
这似乎是 react-hot-loader v4.
中的 bug in react-hot-loader v3 (I was able to reproduce the issue) and it is fixed根据 this comment,此问题似乎是由 react-proxy 中的代理逻辑引起的。一个技巧是存储一个对象来保存你的引用,这将被 react-proxy 复制到代理,并将在 this
:
export default class App extends React.Component {
constructor(props) {
super(props);
this.myRefs = {};
this.setRef = this.setRef.bind(this);
}
componentDidMount() {
console.log('componentDidMount',this.myRefs.div); // <-- Not null!
}
setRef(node) {
this.myRefs.div = node;
console.log('setRef',this.myRefs.div);
};
render() {
return <div ref={this.setRef}>test</div>
}
}
或者如 next comment 中所述,确保您的函数绑定在 componentWillMount
:
export default class App extends React.Component {
constructor(props) {
super(props);
// Do not bind here, "this" will get proxied.
}
// Proxy "this" is now available. Bind here.
componentWillMount() {
this.setRef = this.setRef.bind(this)
}
componentDidMount() {
console.log('componentDidMount',this.div); // <-- Not null!
}
setRef(node) {
this.div = node;
console.log('setRef',this.div);
};
render() {
return <div ref={this.setRef}>test</div>
}
}
我确实用 react-hot-loader v4 验证了有问题的代码,它已修复。
PS: 使用答案作为注释,因为我需要格式化
我能够重现该问题。出现此问题是因为热重新加载程序将代码更改为
setRef = (...params) => this.__setRef__REACT_HOT_LOADER__(...params)
然后在组件prototype
中
__setRef__REACT_HOT_LOADER__(node) {
console.log("setRef called", this, node);
if (this === null) return;
if (node === null) return;
console.log(node);
this.div = node;
}
我认为这打破了 this
链或者这个副本变得不同。有两个变化将起作用
componentDidMount = () => {
console.log('componentDidMount',this.div);
}
如果你使用上面的方法就可以了,因为 get same this then。或者您需要将 setRef 更改为 lambda
return <div ref={ node => this.div=node }>test</div>