2016-05-23 46 views
106

Sto cercando di refactoring del codice seguente dal mio punto di vista di rendering:ReactJS: Attenzione: setstate (...): non può aggiornare nel corso di una transizione di stato esistente

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button> 

ad una versione in cui l'associazione è all'interno del costruttore. Il motivo è che il binding nella visualizzazione di rendering mi darà problemi di prestazioni, specialmente sui telefoni cellulari di fascia bassa.

Ho creato il seguente codice, ma ottengo costantemente i seguenti errori (molti). Sembra che l'applicazione ottiene in un ciclo:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`. 

Di seguito è riportato il codice che uso:

var React = require('react'); 
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); 
var Button = require('react-bootstrap/lib/Button'); 
var Form = require('react-bootstrap/lib/Form'); 
var FormGroup = require('react-bootstrap/lib/FormGroup'); 
var Well = require('react-bootstrap/lib/Well'); 

export default class Search extends React.Component { 

    constructor() { 
     super(); 

     this.state = { 
      singleJourney: false 
     }; 

     this.handleButtonChange = this.handleButtonChange.bind(this); 
    } 

    handleButtonChange(value) { 
     this.setState({ 
      singleJourney: value 
     }); 
    } 

    render() { 

     return (
      <Form> 

       <Well style={wellStyle}> 

        <FormGroup className="text-center"> 

         <ButtonGroup> 
          <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button> 
          <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button> 
         </ButtonGroup> 
        </FormGroup> 

       </Well> 

      </Form> 
     ); 
    } 
} 

module.exports = Search; 

risposta

178

sembra che stai accidentalmente chiamando il metodo handleButtonChange nel metodo di rendering, probabilmente si desidera do onClick={() => this.handleButtonChange(false)} invece.

Se non si desidera creare un lambda nel gestore onClick, penso che sarà necessario disporre di due metodi associati, uno per ciascun parametro.

Nella constructor:

this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true); 
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false); 

E nel metodo render:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button> 
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button> 
+0

ho provato questa soluzione, e funziona. Ma non vedo questa soluzione online come una soluzione preferita. Quello che voglio realizzare è che il mio binding è al di fuori della visualizzazione render. In questa soluzione, this.handleButtonChange = this.handleButtonChange.legare (questo); nel costruttore non è più necessario, vuol dire che il mio binding è di nuovo nella mia visualizzazione render? – user3611459

+2

Forse quello che succede è quando imposto lo stato attivo, attiverà onClick, risultando in un ciclo. c'è un modo per impostare lo stato attivo senza attivare onClick? – user3611459

+2

sei un risparmiatore di vita amico mio. :) – dsaket

0

se si sta cercando di aggiungere argomenti a un gestore in recompose, assicurarsi che si sta definendo le sue argomentazioni correttamente nel gestore. È essenzialmente una funzione al curry, quindi vuoi essere sicuro di richiedere il numero corretto di argomenti. This page has a good example of using arguments with handlers.

Esempio (dal link):

withHandlers({ 
    handleClick: props => (value1, value2) => event => { 
    console.log(event) 
    alert(value1 + ' was clicked!') 
    props.doSomething(value2) 
    }, 
}) 

per il vostro HOC bambino e nel genitore

class MyComponent extends Component { 
    static propTypes = { 
    handleClick: PropTypes.func, 
    } 
    render() { 
    const {handleClick} = this.props 
    return (
     <div onClick={handleClick(value1, value2)} /> 
    ) 
    } 
} 

questo evita scrivendo una funzione anonima dal vostro gestore per cerotto risolvere il problema con non fornisce abbastanza nomi di parametri sul gestore.

1

ho ottenuto lo stesso errore quando stavo chiamando

this.handleClick = this.handleClick.bind(this); 

nel mio costruttore quando handleClick non esisteva

(avevo cancellato e aveva accidentalmente lasciato il "questo" dichiarazione vincolante nel mio costruttore).

Soluzione = rimuovere la "questa" istruzione vincolante.

0

Da reagiscono docs Passing arguments to event handlers

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> 
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>