2016-10-18 7 views
1

Hier wird in meiner App die Funktion 'todoCompleted' aufgerufen, wenn auf Listenelement oder Checkbox geklickt wird. Wenn ich das Kontrollkästchen anklicke, wird der Code nicht korrekt ausgeführt. Die Funktion wird sowohl für das li-Element als auch für das Kontrollkästchen-Feld verwendet.Checkbox toggle in react

class App extends React.Component { 
 

 
    
 

 
      constructor(){ 
 
     super(); 
 
     this.state={ 
 
     todo:[] 
 
     }; 
 
    }; 
 

 
    entertodo(keypress){ 
 
     var Todo=this.refs.inputodo.value; 
 
     if(keypress.charCode == 13) 
 

 
     { 
 
     this.setState({ 
 
      todo: this.state.todo.concat({Value:Todo, checked:false}) 
 

 
     }); 
 
     this.refs.inputodo.value=null; 
 
     }; 
 
    }; 
 
    todo(todo,i){ 
 
     return (
 
     <li className={todo.checked===true? 'line':'newtodo'}> 
 
      <div onClick={this.todoCompleted.bind(this,i)}> 
 
      <input type="checkbox" className="option-input checkbox" checked={todo.checked} /> 
 
      <div key={todo.id} className="item"> 
 
       {todo.Value} 
 
       <div className="Button"> 
 
       <span className="destroy" onClick={this.remove.bind(this, i)}>X</span> 
 
       </div> 
 
      </div> 
 
      </div> 
 
     </li> 
 
    ); 
 
    }; 
 

 
    remove(i){ 
 
     this.state.todo.splice(i,1) 
 
     this.setState({todo:this.state.todo}) 
 
    }; 
 
    todoCompleted(i){ 
 
     var todo=this.state.todo; 
 
     { 
 
     todo[i].checked =true; 
 
     this.setState({ 
 
      todo:this.state.todo 
 
     }); 
 
     } 
 
    }; 
 
    allCompleted=()=>{ 
 
     var todo = this.state.todo; 
 
     var _this = this 
 
     todo.forEach(function(item) { 
 
     item.className = _this.state.finished ? "newtodo" : "line" 
 
     item.checked = !_this.state.finished 
 
    }) 
 
    this.setState({todo: todo, finished: !this.state.finished}) 
 
    }; 
 

 
     render() { 
 
     return (
 
      <div> 
 
      <h1 id='heading'>todos</h1> 
 
      <div className="lines"></div> 
 
       <div> 
 
       <input type="text" ref= "inputodo" onKeyPress={this.entertodo.bind(this)}className="inputodo"placeholder='todos'/> 
 
       <span onClick={this.allCompleted}id="all">x</span> 
 
       </div> 
 
       <div className="mainapp"> 
 
       <ul> 
 
       {this.state.todo.map(this.todo.bind(this))} 
 
       </ul> 
 
       </div> 
 
      </div> 
 
     ); 
 
     } 
 
    } 
 
     
 

 
ReactDOM.render(<App/>,document.getElementById('app'));
.line { 
 
    text-decoration: line-through; 
 
    color: red; 
 
} 
 
.newtodo{ 
 
    text-decoration: none; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script> 
 
<div id="app"></div>

Antwort

1

Die todoCompleted Methode 2 mal aufgerufen wird, wenn Sie auf die Schaltfläche input Element. Es ist auch 3 mal für jedes li Element gebunden: auf li, auf input, und auf button klicken. Als schnelle Lösung, könnten Sie die Struktur Ihres li Element in der folgenden Art und Weise zu formatieren:

Demo hier: http://codepen.io/PiotrBerebecki/pen/bwmwqz

 <li className={text.Decor}> 
     <div onClick={this.todoCompleted.bind(this,i)}> 
      <input type="checkbox" 
       className="option-input checkbox" 
       checked={text.checked} /> 
      <div key={text.id} 
       className="item"> 
      {text.Value} 
      </div> 
     </div> 
     <button type="button" 
       className="destroy" 
       onClick={this.remove.bind(this,i)}> 
      X 
     </button> 
     </li> 

Bitte beachten Sie

  • die neue div Struktur,
  • i wird nun an die remove Methode übergeben, und auch die
  • der todoCompleted Methode ist nur einmal gebunden. Aus Performance-Gründen sollten Sie beim Rendern von JSX die Verwendung von Binde- oder Pfeilfunktionen vermeiden. Dies liegt daran, dass eine Kopie der Ereignisbehandlungsfunktion für jede Instanz erstellt wird, die von der Funktion map() generiert wird. Dies wird hier erklärt:

    remove(i){ 
        this.state.todo.splice(i,1) 
        this.setState({todo:this.state.todo}) 
        }; 
    

    instaed der oben möglich: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

auch Sie den Zustand mutiert wurden

remove(i){ 
    this.setState({ 
     todo: [ 
     ...this.state.todo.slice(0, i), 
     ...this.state.todo.slice(i + 1) 
     ] 
    }); 
    }; 
+0

Ich habe noch eine Frage .. –

+0

I geändert der Code leicht. Anstatt className in todoCompleted zu verwenden, habe ich Änderungen im Listenelement vorgenommen, aber in der Mitte festgeklemmt und nicht gefunden, um es zu korrigieren. –

+0

Ich habe meinen Code in Frage als Referenz aktualisiert. –

0

Sieht aus wie Ihre this.todoCompleted zweimal hier gebrannt (vereinfacht Ihre HTML):

<li onClick={this.todoCompleted.bind(this,i)}> 
    <input type="checkbox" onChange={this.todoCompleted.bind(this,i)} checked={text.checked} /> 
</li> 

Zuerst mit der auf li gebrannt. Es setzt das Kontrollkästchen, um den Status wie gewünscht zu korrigieren. Aber dann, die auf der tatsächlichen Checkbox gefeuert! Und setze Todo zurück in den ungeprüften Zustand. So wie es aussieht ist es nicht :)

arbeiten Sie leicht sehen können, wenn Sie Checkbox aus li Element bewegen, wie ich hier tun: http://www.webpackbin.com/Nk9NTh0RZ