2017-07-18 7 views
1

私はこのクラスを持っています。すべての関数で、これはIdeaクラスのrender()を除くnullに等しくなります。これは常にnullである理由私は理解していないReact "this"は常に関数内でnullです。

class Map extends React.Component { 
 
    render() { 
 
     var handleChange = function (event) { 
 
      this.setState({html: event.target.value}); 
 
     }.bind(this); 
 

 
     return (
 
      <div> 
 
       <Header/> 
 
       <div id="map"> 
 
        {this.props.map.root && (
 
         <Idea html={this.props.map.root.title} idea={this.props.map.root} onChange={handleChange}/> 
 
        )} 
 
       </div> 
 
      </div> 
 
     ); 
 
    } 
 
    }

: 私はReact.js: onChange event for contentEditable

 
 
    class Idea extends React.Component { 
 
    render() { 
 
     return (
 
      <div id="root" 
 
       onInput={this.emitChange} 
 
       onBlur={this.emitChange} 
 
       contentEditable 
 
       dangerouslySetInnerHTML={{__html: this.props.html}}> 
 
      </div> 
 
     ); 
 
    } 
 

 
    shouldComponentUpdate(nextProps) { 
 
     return nextProps.html !== ReactDOM.findDOMNode(this).innerHTML; 
 
    } 
 

 
    componentDidUpdate() { 
 
     if (this.props.html !== ReactDOM.findDOMNode(this).innerHTML) { 
 
      ReactDOM.findDOMNode(this).innerHTML = this.props.html; 
 
     } 
 
    } 
 

 
    emitChange() { 
 
     var html = ReactDOM.findDOMNode(this).innerHTML; 
 
     if (this.props.onChange && html !== this.lastHtml) { 
 

 
      this.props.onChange({ 
 
       target: { 
 
        value: html 
 
       } 
 
      }); 
 
     } 
 
     this.lastHtml = html; 
 
    } 
 
    }

Mapクラスからソリューションを繰り返すようにしようとしました。手伝って頂けますか? ありがとう

答えて

2

コードには多くの問題があります。まず、thisのスコープは、関数beacuseで利用できません。あなたはそれを正しくバインドできません。コンストラクタを使用して、thisを関数にバインドすることができます。このバインディングはちょうど1回発生し、インラインバインディングのすべてのレンダリングに対して繰り返しバインディングを回避します。

ReactがこれらのDOMノードを認識しないため、diffairedを使用してパフォーマンスを向上させることができないため、(より適切な練習のために)dangerouslySetInnerHTMLを使用しないように最大限試してください。レンダリングの中で関数を宣言しないでください。レンダリングが呼び出されるたびに宣言されます。

class Idea extends React.Component { 
 
constructor() { 
 
super(); 
 
    
 
this.emitChange = (e) => this._emitChange(e); 
 
} 
 

 
render() { 
 
    return (
 
     <div id="root" 
 
      onInput={this.emitChange} 
 
      onBlur={this.emitChange} 
 
      contentEditable> 
 
     {this.props.children} 
 
     </div> 
 
    ); 
 
} 
 

 
shouldComponentUpdate(nextProps) { 
 
    return nextProps.html !== ReactDOM.findDOMNode(this).innerHTML; 
 
} 
 

 
componentDidUpdate() { 
 
    if (this.props.html !== ReactDOM.findDOMNode(this).innerHTML) { 
 
     ReactDOM.findDOMNode(this).innerHTML = this.props.html; 
 
    } 
 
} 
 

 
_emitChange() { 
 
    var html = ReactDOM.findDOMNode(this).innerHTML; 
 
    if (this.props.onChange && html !== this.lastHtml) { 
 

 
     this.props.onChange({ 
 
      target: { 
 
       value: html 
 
      } 
 
     }); 
 
    } 
 
    this.lastHtml = html; 
 
} 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

class Map extends React.Component { 
 
constructor() { 
 
super(); 
 
    
 
this.handleChange = (e) => this._handleChange(e); 
 
} 
 
// i dont get why do you store the event in state, if you dont use it. 
 

 
_handleChange = function (event) { 
 
    this.setState({html: event.target.value}); 
 
} 
 

 
render() { 
 
    return (
 
     <div> 
 
      <Header/> 
 
      <div id="map"> 
 
       {this.props.map.root && (
 
        <Idea idea={this.props.map.root} onChange={this.handleChange}> 
 
        {this.props.map.root.title} 
 
        </Idea> 
 
       )} 
 
      </div> 
 
     </div> 
 
    ); 
 
} 
 
}

1

上記のコードスニペットにはいくつかの問題があります。

はまず、あなたはonInput={this.emitChange}のようなものを書き、そしてthisコンテキストが失われることになる - ので(それはhttps://gist.github.com/islahul/73f99302a721a714c002のように、あなたのバベルプリセットセットのサポートで)bind操作を使用するか、新しいダブルコロン構文を使用します。

第2に、基本となるHTML要素は、ref操作で見つかる可能性があります。 <div ref={elm => (this.componentRootDOM = elm)}></div>のようなものを使用してから、リアクションライフサイクル機能のためにthis.componentRootDOMを呼び出します。

2

これをレンダリング機能でトリガーされる関数にバインドする必要があります。コンポーネントのコンストラクタ関数を追加することをお勧めします(ベストプラクティスは、最初の関数として追加することです)。

class Idea extends React.Component { 
    constructor(props) { 
    super(props); 
    this.emitChange = this.emitChange.bind(this); 
    } 
    ... 
} 
1

のではなく、本質的にこれになってきて、あなたもproperty initializer syntaxを使用してemitChangeを宣言することができ、代替として、bindメソッドを使用して:

_emitChange =() => { 
    var html = ReactDOM.findDOMNode(this).innerHTML; 
    if (this.props.onChange && html !== this.lastHtml) { 

     this.props.onChange({ 
      target: { 
       value: html 
      } 
     }); 
    } 
    this.lastHtml = html; 
}; 

どちらの手法をバインドする方法が1つだけの場合でも、より多くのメソッドがある場合は、プロパティ初期化子の構文によって、コンストラクタに膨らみが生じる可能性があります。

関連する問題