React.js ES6는 'this'를 모든 메소드에 바인딩하지 않습니다.
최근에 저는 React.js를 다루기 시작했고 그것을 좋아합니다. 나는 일반 ES5에서 시작했고, 요령을 이해하기 위해 문서는 모두 ES5로 작성되었습니다.
하지만 지금은 ES6를 사용 해보고 싶었습니다. 왜냐하면 그것은 빛나고 새롭고 일부를 단순화하는 것 같기 때문입니다. 나를 많이 괴롭히는 것은 구성 요소 클래스에 추가 한 모든 메서드에 대해 이제 'this'를 바인딩해야한다는 것입니다. 그렇지 않으면 작동하지 않습니다. 그래서 내 생성자는 다음과 같이 보입니다.
constructor(props) {
super(props);
this.state = { ...some initial state... }
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
this.someHandler = this.someHandler.bind(this);
}
수업에 더 많은 메소드를 추가하면 더 크고 추악한 엉망이 될 것입니다.
제 질문은이 문제를 해결할 수있는 방법이 있습니까, 아니면 적어도 더 쉽고 짧고 덜 추하게 만들 수 있습니까? 내가 ES6와 함께 React를 시도하고 싶었던 주된 이유 중 하나는 내 코드를 더 간결하게 만드는 것이었지만 이것은 그 반대입니다. 어떤 제안이나 의견을 주시면 감사하겠습니다.
클래스 필드 를 사용 하여 생성자 외부에서 바인딩을 수행 할 수 있습니다 . 다음과 같이 보입니다.
class Foo extends React.Component {
handleBar = () => {
console.log('neat');
};
handleFoo = () => {
console.log('cool');
};
render() {
return (
<div
onClick={this.handleBar}
onMouseOver={this.handleFoo}
/>
);
}
}
클래스 필드는 클래스 속성 transform을 통해 Babel에서 실험적으로 지원 되지만 아직 Babel 사전 설정이 아닌 Stage 3 Draft 이기 때문에 여전히 "실험적" 입니다.
그러나 ES7까지 또는 Babel에서 기능을 활성화 할 때까지 수동으로 바인딩을 수행해야합니다. 이 주제는 ES6 +의 React에 대한 Babel의 블로그 게시물에서 간략하게 다룹니다 .
또 다른 대안은 데코레이터를 사용하는 것입니다. 프로토 타입에서 getter를 선언하고 인스턴스에 대한 첫 번째 액세스에서 해당 함수의 바인딩 된 버전으로 고유 한 속성을 정의합니다.
하지만 문제가 있습니다! 개발 중에는 속성을 대체하지 않으며 모든 액세스에 바인딩됩니다. 이것은 react-hot-loader를 중단하지 않음을 의미합니다 . 적어도 나에게는 그것은 꽤 중요합니다.
이를 제공 하는 라이브러리 인 class-bind를 만들었습니다 .
import {bound} from 'class-bind';
class App {
constructor(){
this.foo = 'bar';
}
@bound
returnsFoo(){
return this.foo;
}
render(){
var returnsFoo = this.returnsFoo;
return (
<div>
{returnsFoo()} === 'bar'
</div>
);
}
}
데코레이터가 너무 불안정한가요? 동일한 이점으로 모든 또는 일부를 묶을 수 있습니다.
import {bind, bindAll} from 'class-bind';
bind(App.prototype, 'returnsFoo');
// or
bindAll(App.prototype);
Ssorallen의 제안은 훌륭하지만 다른 방법을 원한다면 다음이 있습니다.
class AppCtrlRender extends Component {
binder(...methods) { methods.forEach( (method) => this[method] = this[method].bind(this) ); }
render() {
var isMobile = this.state.appData.isMobile;
var messages = this.state.appData.messages;
return (
<div id='AppCtrlSty' style={AppCtrlSty}>
React 1.3 Slider
<br/><br/>
<div className='FlexBoxWrap'>
<Slider isMobile={isMobile}/>
<JList data={messages}/>
</div>
</div>
);
}
}
var getAppState = function() {
return {
appData: AppStore.getAppData()
};
};
export default class AppCtrl extends AppCtrlRender {
constructor() {
super();
this.state = getAppState();
this.binder('appStoreDidChange');
}
componentDidMount() {
var navPlatform = window.navigator.platform;
Actions.setWindowDefaults(navPlatform);
}
componentWillMount() { AppStore.onAny(this.appStoreDidChange); }
componentWillUnmount() { AppStore.offAny(this.appStoreDidChange); }
appStoreDidChange() { this.setState(getAppState()); }
}
this.binder ( 'method1', 'method2', ...)에 원하는 수의 메소드를 추가 할 수 있습니다.
사용 stage-0
하는 경우 함수 바인딩 구문이 있습니다.
class MyComp extends Component {
handleClick() { console.log('doing things') }
render() {
return <button onClick={::this.handleClick}>Do Things</button>
}
}
This destructures to this.handleClick.call(this)
, which I think is generally performant enough.
One idea to avoid bind
class MyComp extends Component {
render() {
return <button onClick={e => this.handleClick(e)}>Do Things</button>
}
}
disclaimer: untested, also, cannot easily handle more than one argument (in this case, there is one, event (e).
Also, this is answer is probably an example of what not to do, according to this article which is probably a worthwhile read:
https://daveceddia.com/avoid-bind-when-passing-props/
I actually prefer to imitate OOP inheritance by passing children the parent context.
class Parent extends Component {
state = {happy: false}
changeState(happy) {
this.setState({happy})
}
render() {
return (
<Child parent={this} >
)
}
}
class Child extends Component {
//...
this.props.parent.changeState(true)
}
$0.02, Jon
I created a method to organize all the "binds".
class MyClass {
constructor() {
this.bindMethods([
'updateLocationFields',
'render',
'loadCities',
]);
}
bindMethods(methods) {
methods.forEach((item) => {
this[item] = this[item].bind(this);
});
}
...
}
I use a helper function doBinding(this)
, which I call in each constructor. In this example it binds _handleChange1()
and _handleChange2()
.
class NameForm extends React.Component {
constructor(props) {
super(props);
doBinding(this);
this.state = {value1: "", value2: ""};
}
_handleChange1(event) {
this.setState({value1: event.target.value});
}
_handleChange2(event) {
this.setState({value2: event.target.value});
}
render() {
...
}
}
The method works even if you are not using Babel.
My handler methods all begin with _
(a convention to indicate they are private). So doBinding()
looks for the _
. You can remove the if (key.startsWith("_"))
if you don't use this convention.
function doBinding(obj) {
const proto = Object.getPrototypeOf(obj);
for (const key of Object.getOwnPropertyNames(proto)) {
if (key.startsWith("_")) {
obj[key] = obj[key].bind(obj);
}
}
}
참고URL : https://stackoverflow.com/questions/32192682/react-js-es6-avoid-binding-this-to-every-method
'Development Tip' 카테고리의 다른 글
__init__.py 사용 (0) | 2020.11.18 |
---|---|
스캐 폴딩 컨트롤러가 Visual Studio 2013 업데이트 2에서 작동하지 않습니다. (0) | 2020.11.18 |
C ++의 가비지 컬렉션 라이브러리 (0) | 2020.11.18 |
Haskell의 Stream Fusion이란? (0) | 2020.11.18 |
MSI 설정은 어떻게 생성합니까? (0) | 2020.11.18 |