> 웹 프론트엔드 > JS 튜토리얼 > 이것을 React 컴포넌트에 바인딩하는 이유 분석

이것을 React 컴포넌트에 바인딩하는 이유 분석

不言
풀어 주다: 2018-07-21 10:27:45
원래의
1355명이 탐색했습니다.

이 글은 왜 React 컴포넌트 방식으로 바인딩되어야 하는지 알려드립니다. 내용이 매우 좋습니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

프론트엔드 개발에 React를 사용해 본 적이 있다면 다음 코드를 본 적이 있을 것입니다. React进行前端开发,一定见过下面这样的代码:

//假想定义一个ToggleButton开关组件
class ToggleButton extends React.Component{
    constructor(props){
        super(props);
        this.state = {isToggleOn: true};
        this.handleClick = this.handleClick.bind(this); 
        this.handleChange = this.handleChange.bind(this);
    }
    handleClick(){
        this.setState(prevState => ({
            isToggleOn: !preveState.isToggleOn
        }));
    }
    handleChange(){
        console.log(this.state.isToggleOn);
    }
    render(){
        return(
           <button onClick={this.handleClick} onChange={this.handleChange}>
                {this.state.isToggleOn ? &#39;ON&#39;:&#39;OFF&#39;}
            </button>
        )
    }
}
로그인 후 복사

构造方法中为什么要给所有的实例方法绑定this呢?

1. 代码执行的细节

上例仅仅是一个组件类的定义,当在其他组件中调用或是使用ReactDOM.render( )方法将其渲染到界面上时会生成一个组件的实例,因为组件是可以复用的,面向对象的编程方式非常适合它的定位。根据this指向的基本规则就可以知道,这里的this最终会指向组件的实例。

组件实例生成的时候,构造器constructor会被执行,此处着重分析一下下面这行代码:

this.handleClick = this.handleClick.bind(this);
로그인 후 복사

此时的this指向新生成的实例,那么赋值语句右侧的表达式先查找this.handleClick( )这个方法,由对象的属性查找机制(沿原型链由近及远查找)可知此处会查找到原型方法this.handleClick( ),接着执行bind(this),此处的this指向新生成的实例,所以赋值语句右侧的表达式计算完成后,会生成一个指定了this的新方法,接着执行赋值操作,将新生成的函数赋值给实例的handleClick属性,由对象的赋值机制可知,此处的handleClick会直接作为实例属性生成。总结一下,上面的语句做了一件这样的事情:

把原型方法handleClick( )改变为实例方法handleClick( ),并且强制指定这个方法中的this指向当前的实例。

2. ES5的写法中为什么不用bind(this)?

ES5的写法是指使用React.createClass( )方法来定义组件,React在V16以上的新版本中已经移除了这个API,你可以通过阅读更早版本的源代码看到这个方法的细节。

  //旧版本`react`中`createClass`方法片段
  if (this.__reactAutoBindMap) {
        this._bindAutoBindMethods();
  }
로그인 후 복사

在老版本的React中,createClass()的定义中可以看到上面的代码,抛开其他复杂的逻辑,从方法名就可以看出这是一个自动绑定的方法,实际上在这个方法中所完成的,就是对组件中自定义方法的this强制绑定,感兴趣的读者可以自行翻看源码了解细节。

3. 绑定this的必要性

在组件上绑定事件监听器,是为了响应用户的交互动作,特定的交互动作触发事件时,监听函数中往往都需要操作组件某个状态的值,进而对用户的点击行为提供响应反馈,对开发者来说,这个函数触发的时候,就需要能够拿到这个组件专属的状态合集(例如在上面的开关组件ToggleButton例子中,它的内部状态属性state.isToggleOn的值就标记了这个按钮应该显示ON或者OFF),所以此处强制绑定监听器函数的this指向当前实例的也很容易理解。

React构造方法中的bind会将响应函数与这个组件Component进行绑定以确保在这个处理函数中使用this时可以时刻指向这一组件的实例。

4. 如果不绑定this

如果类定义中没有绑定this的指向,当用户的点击动作触发this.handleClick( )这个方法时,实际上执行的是原型方法,可这样看起来并没有什么影响,如果当前组件的构造器中初始化了state这个属性,那么原型方法执行时,this.state会直接获取实例的state属性,如果构造其中没有初始化state这个属性(比如React中的UI组件),说明组件没有自身状态,此时即使调用原型方法似乎也没什么影响。

事实上的确是这样,这里的bind(this)所希望提前规避的,就是著名的this指针丢失的问题

例如使用解构赋值的方式获取某个属性方法时,就会造成引用转换丢失this的问题:

const toggleButton = new ToggleButton();

import {handleClick} = toggleButton;
로그인 후 복사

上例中解构赋值获取到的handleClick这个方法在执行时就会报错,Class的内部是强制运行在严格模式下的,此处的this在赋值中丢失了原有的指向,在运行时指向了undefined,而undefined是没有属性的。

另一个存在的限制,是没有绑定this的响应函数在异步运行时可能会出问题,当它作为回调函数被传入一个异步执行的方法时,同样会因为丢失了thisrrreee

왜 해야 할까요? 프론트엔드 개발을 위해 React를 사용해야 하나요? 이것을 모든 인스턴스 메소드에 바인딩하는 것은 어떻습니까? #🎜🎜#

1. 코드 실행 내용

#🎜🎜#위의 예는 다른 컴포넌트에서 호출하거나 ReactDOM.render를 사용하는 경우에 대한 정의일 뿐입니다. ( ) 메서드는 구성 요소를 인터페이스에 렌더링할 때 구성 요소의 인스턴스를 생성합니다. 구성 요소는 재사용이 가능하므로 개체 지향 프로그래밍은 구성 요소 위치 지정에 매우 적합합니다. 이 항목 지정의 기본 규칙에 따르면 여기의 이 항목이 결국 구성 요소의 인스턴스를 가리킨다는 것을 알 수 있습니다. #🎜🎜##🎜🎜#구성 요소 인스턴스가 생성되면 constructor 생성자가 실행됩니다. 여기서는 다음 코드 줄을 분석하는 데 중점을 둡니다. #🎜🎜#rrreee#🎜🎜#At 이번에는 this가 새로 생성된 인스턴스를 가리킨 다음 할당 문의 오른쪽에 있는 표현식이 먼저 this.handleClick( ) 메서드를 검색합니다. 이는 다음과 같이 결정됩니다. 객체의 속성 검색 메커니즘(근거리 및 원거리 검색에 의한 프로토타입 체인을 따라) 프로토타입 메소드 this.handleClick( )이 여기에서 발견될 것임을 알 수 있습니다. bind(this)가 실행됩니다. 여기서 this는 새로 생성된 인스턴스를 가리키므로 할당문 오른쪽의 식이 계산된 후 다음을 지정하는 새 메서드가 생성됩니다. this가 생성되고 새 함수를 추가하기 위한 할당 작업이 수행됩니다. 생성된 함수는 할당 메커니즘에 따라 인스턴스의 handleClick 속성에 할당됩니다. 객체, 여기에서 handleClick은 인스턴스 속성으로 직접 생성됩니다. 요약하면 위의 명령문은 다음과 같은 작업을 수행합니다. #🎜🎜##🎜🎜#프로토타입 메서드 handleClick( )를 인스턴스 메서드 handleClick( ) code로 변경합니다. >, 이 메서드의 <code>this가 현재 인스턴스를 가리키도록 강제합니다. #🎜🎜#

2. ES5 작성에서 왜 바인드(this)를 사용하지 않나요?

#🎜🎜#ES5 작성 방법은 React.createClass( )를 사용하는 것을 의미합니다. > 컴포넌트를 정의하는 메소드입니다. React는 V16 이상의 새 버전에서 이 API를 제거했습니다. 이전 버전의 소스 코드를 읽으면 이 메소드의 세부사항을 볼 수 있습니다. #🎜🎜#rrreee#🎜🎜#React의 이전 버전에서는 다른 복잡한 로직을 제외하고 createClass() 정의에서 위 코드를 볼 수 있습니다. 메소드 이름에서 알 수 있듯이 이는 자동 바인딩 메소드입니다. 실제로 이 메소드에서 수행되는 작업은 컴포넌트에서 사용자 정의 메소드의 를 강제로 바인딩하는 것입니다. 자세한 내용은 소스 코드를 직접 확인하세요. #🎜🎜#

3. 바인딩의 필요성

#🎜🎜#구성 요소의 이벤트 리스너 바인딩은 특정 대화형 작업이 이벤트를 트리거할 때 응답하는 것입니다. 사용자의 클릭 동작에 대한 응답 피드백을 제공하기 위해 구성 요소의 특정 상태 값을 조작하려면 개발자의 경우 이 기능이 트리거될 때 이 구성 요소에 대한 독점 상태 컬렉션을 얻을 수 있어야 합니다(예: 위 스위치 구성 요소 ToggleButton의 예에서 내부 상태 속성 state.isToggleOn의 값은 버튼이 ON 또는 OFF )이므로 필수 바인딩 리스너 함수의 this가 현재 인스턴스를 가리키는 것을 이해하기 쉽습니다. #🎜🎜#
#🎜🎜#React 생성자의 바인딩은 응답 함수를 구성 요소 구성 요소에 바인딩하여 이 핸들러 함수에서 이를 사용할 때 항상 이 구성 요소의 인스턴스를 가리킬 수 있도록 합니다. #🎜🎜#

4. 이것이 바인딩되지 않은 경우

#🎜🎜#this에 대한 포인터가 클래스 정의에 바인딩되어 있지 않으면 트리거됩니다. 사용자가 this.handleClick( )을 클릭할 때 이 메서드를 사용하면 실제로 프로토타입 메서드가 실행되지만 state하고 프로토타입 메소드가 실행될 때 this.state는 해당 속성의 state 속성을 ​​직접 얻습니다. 인스턴스 생성 시 상태 초기화가 없는 경우 이 속성(예: React의 UI 구성 요소)은 해당 구성 요소에 자체 상태가 없음을 나타냅니다. 효과가 없도록. #🎜🎜##🎜🎜#사실 이것이 사실입니다. 여기서 bind(this)가 미리 피하고 싶은 것은 이 포인터가 누락되는 유명한 문제입니다. . #🎜🎜##🎜🎜#예를 들어 특정 속성 메서드를 얻기 위해 구조 분해 할당을 사용하면 참조 변환에서 이 메서드가 손실되는 문제가 발생합니다. #🎜🎜#rrreee#🎜🎜# 위의 예에서 할당을 구조화하여 얻은 handleClick 메서드는 실행 시 오류를 보고합니다. Class의 내부는 강제로 엄격 모드에서 실행됩니다. 여기서는 이렇습니다. code>는 할당 중에 원래 포인터를 잃어 런타임에 <code>undefine을 가리키며 undefine에는 속성이 없습니다. #🎜🎜##🎜🎜# 또 다른 제한 사항은 this를 바인딩하지 않은 응답 함수가 비동기 실행 시 문제를 일으킬 수 있다는 것입니다. 콜백 함수 메서드로 비동기 실행에 전달되면 오류도 발생합니다. this에 대한 포인터가 손실되었기 때문에 발생합니다. #🎜🎜#

구성요소 인스턴스 메소드에 대해 this에 대한 필수 지정이 없으면 참조 변환 또는 을 안전하게 사용할 수 없습니다. 나중에 사용할 때 콜백 함수로 사용하세요. 전송이 방법은 이후 사용 및 공동 개발에 불편합니다. this,在将来的使用中就无法安心使用引用转换作为回调函数传递这样的方式,对于后续使用和协作开发而言都是不方便的。

5. 小结

this的使用非常灵活,但这种灵活性也带来了很多混乱。这里的bind(this)是为了改进javascript语言级的缺陷,并不是只有React中才需要这样做,这个问题是伴随着面向对象编程而产生的,在使用javascript进行插件和框架的开发时,这个问题的影响会更加明显。之所以说它是一个语言级的缺陷,是因为Java中对于this在同样场景下的指向更符合正常思维逻辑,而javascript

5. 요약

this의 사용은 매우 유연하지만 이러한 유연성은 많은 혼란을 가져옵니다. 여기서 bind(this)는 JavaScript의 언어 수준 결함을 개선하기 위한 것입니다. 이는 React에서만 필요한 것이 아닙니다. javascript를 사용할 때 발생하는 문제입니다. 이 문제의 영향은 플러그인과 프레임워크를 개발할 때 더욱 분명해집니다. 언어 수준의 결함이라고 말하는 이유는 Java의 동일한 시나리오에서 this를 가리키는 것이 일반적인 사고 논리와 더 일치하지만 >javascript 바인딩이 코드에 표시되지 않으면> 언어 연산 결과가 메소드 이름과 일치하지 않습니다. <p><br>관련 추천 : </p> <p><a href="http://www.php.cn/js-tutorial-406769.html" target="_blank" title="React中动画不生效的原因分析"></a> React에서 애니메이션이 적용되지 않는 이유 분석<br></p>#🎜🎜 ##🎜🎜 #<p>React 사용: React 구성 요소 내부의 상태 관리<a href="http://www.php.cn/js-tutorial-406756.html" target="_blank" title="React的使用:React组件内部的状态管理"></a><br></p>

위 내용은 이것을 React 컴포넌트에 바인딩하는 이유 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿