Chrome,Firefox 调试器未在 React 应用程序中显示 'this' 的正确值

Chrome, Firefox debuggers not displaying the correct value for 'this' in a react app

这里有一些代码,在一个 React 组件中 class(使用 CRA 2 搭建的脚手架)

  click = () => {
    console.log(this, "hello");
    let x = 1 + 1; //This is just here to let chrome put a break point here. 
  }

当这段代码运行时,它会将组件对象打印到控制台。

但是 - 如果我将调试器附加到该点,Chrome (68) 和 Firefox (63) 都会将 'this' 显示为未定义。

这是怎么回事?

是否与用于将点击创建为 class 属性 的 transform-class-properties babel 插件有关?

编辑: 是的,确实如此。

如果我们手动绑定这样的方法:

  constructor() {
    super();
    this.click2 = this.click2.bind(this);
  }

  click2() {
    console.log(this, "hello");
    let x = 1 + 1;
  }

然后就可以正常工作了。

无论如何 - 有没有一种方便的方法可以解决这个问题,这样我就不必把所有那些绑定语句都放进去?

我创建了一个 example on CodeSandbox,我认为它重现了您的问题,但我不确定。如果没有,请创建您自己的示例。相关代码如下。

在此示例中,代码运行良好。如您所料,console.log(this, "hello") 记录一个 Square 对象 + "hello"。如果在 let y = 2 + 2 行放置断点,Chrome 调试器将显示

this: undefined
x: 2
y: undefined

当然,y是未定义的,因为let y语句还没有执行。 x 已按预期定义。 this 是未定义的,因为 React 和 Babel 在幕后跳过了很多圈套,而 this 实际上是未定义的。如果要从调试器访问 this,则需要使用 _this。事实上,即使您在行 let y = 2 + 2 上放置了一个断点,那也不是正在执行的实际源代码或实际断点所在的位置。您所看到的是 source map 提供的便利,它允许您查看您编写的代码并在其上设置断点,尽管实际代码 运行 完全不同(由巴别塔等)。

我写的代码是:

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null
    };
  }

  click = () => {
    console.log(this, "hello");
    let x = 1 + 1; //This is just here to let chrome put a break point here.
    let y = 2 + 2; //This is just here to let chrome put a break point here.
  };

  render() {
    return (
      <button className="square" onClick={this.click}>
        {this.props.value}
      </button>
    );
  }
}

实际上 运行ning 的代码是:

var Square =
/*#__PURE__*/
function (_React$Component) {
  (0, _inherits2.default)(Square, _React$Component);

  function Square(props) {
    var _this;

    (0, _classCallCheck2.default)(this, Square);
    _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Square).call(this, props));
    (0, _defineProperty2.default)((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "click", function () {
      console.log((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)), "hello");
      var x = 1 + 1; //This is just here to let chrome put a break point here.

      var y = 2 + 2; //This is just here to let chrome put a break point here.
    });
    _this.state = {
      value: null
    };
    return _this;
  }

  (0, _createClass2.default)(Square, [{
    key: "render",
    value: function render() {
      return _react.default.createElement("button", {
        className: "square",
        onClick: this.click
      }, this.props.value);
    }
  }]);
  return Square;
}(_react.default.Component);

由于 React.js 内部结构(特别是它包装事件的方式),在调用处理程序时,this 未定义。如果您查看调用堆栈,您会发现 executeDispatch 调用 invokeGuardedCallbackAndCatchFirstErrorcontext 对象的显式值为 undefined,最终值为 this 在回调中。 React 和 Babel 试图在您编写代码时向您隐藏所有这些,但它们无法完全向调试器隐藏这些,特别是关于 this,因此在这种情况下您必须转到实际代码中才能看到您需要在调试器中引用 _this

我认为您需要设置 babel 选项来禁用模块处理。看到这个答案:

在你的 .babelrc 中:

{
  "presets": [
    [ "es2015", { "modules": false } ]
  ]
}

一个务实的选择 - 如果你想做的是在某个点检查反应组件的 state/props,就是按照正常情况进入断点 - 但不是使用调试器检查状态 - 使用 react dev tools 插件实际检查状态。

这可能有点繁琐,但这是一个选择。