咱们先来看看下面这个组件:node
import React from 'react' class App extends React.Component { constructor(props) { super(props) this.textInput = null } handleClick() { this.textInput.focus() } render() { return ( <div> <input type="text" ref={(node) => {this.textInput = node}}/> <input type="button" value="foucs" onClick={this.handleClick.bind(this)}/> </div> ) } } export default App
该组件的功能是点击focus
按钮会使input
框聚焦,我在ref
中使用了箭头函数回调,在onClick
中使用bind
绑定函数,但咱们很不建议在jsx
属性中使用箭头函数和bind
,缘由有如下两点:react
PureComponent
,或者本身实现了 shouldComponentUpdate
方法,使用对象比较的方式来决定是否要从新渲染组件,那么组件属性中的箭头函数就会让该方法永远返回真值,引发没必要要的重复渲染。那么,咱们如何来解决上面问题呢?很简单,将箭头函数和bind
外移就好了git
import React from 'react' class App extends React.Component { constructor(props) { super(props) this.textInput = null this.setTextInputRef = element => { this.textInput = element } } handleClick = () => { this.textInput.focus() } render() { return ( <div> <input type="text" ref={this.setTextInputRef}/> <input type="button" value="foucs" onClick={this.handleClick}/> </div> ) } } export default App
咱们将setTextInputRef
和handleClick
都是用箭头函数实现,就避免了去绑定this
,这是 JS
中的一个实验中的特性,这意味着她尚未被 ECMAScript
的标准所采纳,不过在它被采纳以前,你能够配置 babel
,使用 @babel/plugin-proposal-class-properties
来转换它。咱们来配置试试:es6
.babelrc
配置以下:github
{ "presets": [ "@babel/preset-env", "@babel/preset-react" ], "plugins": [ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties" ] }
执行npx babel ./src/index.js -o ./dist/compiled.js
,而后打开compiled.js
babel
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var App = /*#__PURE__*/ function (_React$Component) { (0, _inherits2["default"])(App, _React$Component); function App(props) { var _this; (0, _classCallCheck2["default"])(this, App); _this = (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(App).call(this, props)); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "handleClick", function () { _this.textInput.focus(); }); _this.textInput = null; _this.setTextInputRef = function (element) { _this.textInput = element; }; return _this; } (0, _createClass2["default"])(App, [{ key: "render", value: function render() { return _react["default"].createElement("div", null, _react["default"].createElement("input", { type: "text", ref: this.setTextInputRef }), _react["default"].createElement("input", { type: "button", value: "foucs", onClick: this.handleClick })); } }]); return App; }(_react["default"].Component); var _default = App; exports["default"] = _default;
咱们能够看到类方法的箭头函数被成功转译。就不须要担忧支不支持了。函数
既然咱们建议在jsx
属性中不要使用箭头函数和绑定,可是咱们可能在编写代码过程当中因为习惯写了箭头函数或者绑定,有没有什么工具能够帮助咱们检测呢,显然eslint
能够作到这一点,咱们只须要安装eslint-plugin-react
插件,并配置react/jsx-no-bind
规则,详细以下:工具
module.exports = { "env": { "browser": true, "es6": true, "node": true }, "extends": "eslint:recommended", "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": [ "react" ], "rules": { "react/jsx-no-bind": ["error", { "ignoreDOMComponents": false, "ignoreRefs": false, "allowArrowFunctions": false, "allowFunctions": false, "allowBind": false }] } };
当咱们执行npx eslint ./src/index.js
,将会报下面错误ui
参考:
https://www.freecodecamp.org/news/react-pattern-extract-child-components-to-avoid-binding-e3ad8310725e/
https://stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind
http://www.javashuo.com/article/p-vurzalix-kb.html
https://www.w3ctech.com/topic/2096
https://babeljs.io/docs/en/babel-plugin-proposal-class-properties
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.mdthis