咱們先來看看下面這個組件: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