2017-06-01 2 views
0

Ich bin neu zu Reagieren und habe jetzt Probleme.Fehlender Statuswert nach Funktionsbindung in React

export default class Header extends React.Component { 
 
    constructor(props) { 
 
    super(props) 
 
    this.state = { 
 
     variants: props.variants, 
 
     background: props.variants[0].background 
 
    } 
 
    } 
 
    setTimer() { 
 
    const { variants } = this.state 
 
    clearTimeout(this.timeout) 
 
    this.timeout = setTimeout(this.updateBackground.bind(this), 1000) 
 
    } 
 
    updateBackground() { 
 
    console.log(`Keys ${this.state.variants}`); 
 
    const { variants } = this.state 
 
    const { background } = variants[parseInt(Math.random() * 5)] 
 
    setState({ 
 
     background: background 
 
    }, this.setTimer) 
 
    } 
 
    componentDidMount() { 
 
    this.setTimer() 
 
    } 
 
    render() { 
 
    const { background } = this.state 
 
    return (
 
      <div className="header-image"> <img src={ background } /> </div> 
 
    ) 
 
    } 
 
}
<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>

Mein Problem ist: Zustand zu ändern, wenn in wenigen Sekunden
Ich habe Komponente, die einen Gegenstand als Requisiten und einige Funktionen fängt nach

this.updateBackground.bind(this) 

Anruf, updateBackground hat alle Statuswerte verloren, z

this.state.variants 

definiert ist, aber es ist nicht mehr enthält Objekte, z

this.state.variants[0] === undefined 

Erklären Sie mir bitte, was ich falsch mache :)

+2

Es sollte 'this.setState' – Li357

+0

warum Sie nicht verwenden setInterval statt SetTimeout? – vijayst

+0

@AndrewLi, Problem ist früher als this.setState, this.state.variants [0] .background ist undefined –

Antwort

0

ich hier ein wenig bin zu raten. Die Varianten in Requisiten können anfangs leer sein. Wenn die Requisiten ändern werden, setzen Zustand in componentWillReceiveProps

componentWillReceiveProps(nextProps) { 
    if (nextProps.variants !== this.props.variants) { 
    this.setState({ variants: nextProps.variants }); 
    } 
} 

Die andere Option ist, was Tom Davies vorgeschlagen. Benutze die Requisiten direkt.

updateBackground() { 
    const { variants } = this.props 
    const { background } = variants[parseInt(Math.random() * 5)] 
    this.setState({ 
     background 
    }, this.setTimer); 
    } 
+0

Das Problem ist, welche Komponente erhielt Requisiten, ich überprüfe dies in setTimer-Funktion, aber wenn ich von setTimer Funktion updat aufrufen eBackground, es hat keine Requisiten. –

0

Das Problem ist, diese Zeile Code

this.timeout = setTimeout(this.updateBackground.bind(this), 1000) 

Wenn Sie setTimeout nennen, in dem Moment, Sie binden, verloren Sie den Umfang der Klasse. Versuchen Sie, diese

constructor(props) { 
    super(props) 
    this.state = { 
     variants: props.variants, 
     background: props.variants[0].background 
    } 
    this.updateBackground = this.updateBackground.bind(this) 
    } 

Und

this.timeout = setTimeout(() => this.updateBackground(), 1000) 
+0

Leider hilft mir diese Lösung nicht ( –

+0

) Selbst wenn Sie versuchen, Requisiten und Status als Parameter an Ihre Funktion zu übergeben? 'SetTimeout (() => this.updateBackground (Zustand, Requisiten), 1000)' um sie zu extrahieren – Ematipico

0

Sie können schon einige Änderungen vornehmen, die Lesbarkeit und Wartbarkeit Ihrer Komponente zu verbessern. Ich habe angenommen, dass es alle 1000ms aktualisieren sollte und stattdessen setInterval verwenden, um zu vermeiden, den Zeitgeber zurücksetzen zu müssen - da das Aktualisieren des Abbilds sowieso kein lang andauernder Vorgang ist.

Zusätzlich habe ich die Handhabung für das Aushängen der Komponente hinzugefügt, um zu verhindern, dass das Intervall/der Timer weiterhin ausgeführt wird und auf eine Komponente reagiert, die nicht mehr vorhanden ist.

Komponente

export default class Header extends React.Component { 

    constructor(props) { 
     super(props); 

     // We can just use props, don't need to copy variants 
     // into state since it's never changed. 
     this.state = { 
      currentBackground: props.variants[0].background, 
      intervalId: null 
     }; 

     // I'll bind everything in the constructor, so it's 
     // only done once and removes clutter from methods. 
     this.updateBackground = this.updateBackground.bind(this); 
    } 

    componentDidMount() { 
     // Do everything we need to on startup here, since it's only 
     // setting the update interval, won't break it out into 
     // separate functions. 
     this.setState({ 
      intervalId: setInterval(() => this.updateBackground(), 1000) 
     }); 
    } 

    componentWillUnmount() { 
     // When the component is unmounted, stop the interval. 
     clearInterval(this.state.intervalId); 
    } 

    updateBackground() { 
     // Assuming you wanted a whole number here, in which case 
     // floor() makes more sense than parseInt(). We should use 
     // variants.length rather than assuming there are 5 entries. 
     let index = Math.floor(Math.random() * this.props.variants.length); 

     this.setState({ 
      currentBackground: this.props.variants[index].background 
     }) 
    } 

    render() { 
     // Somewhat opinionated, but there doesn't seem to be any reason 
     // to wrap this in a <div>. You could then rename this component 
     // and reuse it anywhere you wanted a random image. 
     return <img className="header" src={this.state.currentBackground} />; 
    } 
} 

Header.propTypes = { 
    variants: React.PropTypes.array.isRequired 
}; 

wie Called ...

<Header variants={[{ background: 'abc.png' }, { background: 'def.png' }]} /> 
+0

Ich benutze deinen Code und bekomme den gleichen Fehler "Uncaught TypeError: Kann nicht 'Hintergrund' von undefined" –

+0

@NikitaGoncharov lesen, gab es einen Tippfehler in der PropTypes-Deklaration (behoben, wenn Sie es erneut versuchen möchten) - das Das Problem, das Sie beschrieben haben, hätte aber nicht das Problem verursacht: Es klingt, als würden Sie ein Array von Strings anstelle von Objekten übergeben. Wie sieht render() in der Komponente aus, in der Sie Header verwenden? –

Verwandte Themen