2016-11-10 248 views
0

我正在學習反應,並遵循本教程:https://scotch.io/tutorials/build-a-react-flux-app-with-user-authentication向我的應用添加身份驗證。React組件在狀態更改後不重新渲染

完成之後可悲的是,我意識到它僅更新登錄按鈕,你必須刷新瀏覽器中看到的認證內容。

我已經找遍了,並試圖設置狀態和道具,並通過他們從父母到孩子,但都無濟於事。

下面是我的三個組成部分,大規模讚賞任何幫助,我看過所有網站上&研究相互反應Apps中已。

謝謝。

App.js

import 'normalize.css/normalize.css'; 
import 'bootstrap/dist/css/bootstrap.min.css'; 

import React, { Component } from 'react'; 
import PlayButton from './PlayButton'; 
import SlotMachine from './SlotMachine'; 

import AuthActions from '../actions/AuthActions'; 
import AuthStore from '../stores/AuthStore'; 



class AppComponent extends Component { 



    componentWillMount() { 
     this.lock = new Auth0Lock('3RhBq3qZaZARDQae7PtbH59wyP9xe7Ld', 'wolftiger.eu.auth0.com'); 
    } 

    constructor(props) { 
     super(props); 
     this.state = { 
      authenticated: AuthStore.isAuthenticated() 
     } 
    } 


    login() { 
     // We can call the show method from Auth0Lock, 
     // which is passed down as a prop, to allow 
     // the user to log in 
     //console.log("parent login", this.props); 
     this.props.lock.show((err,profile,token) => { 
      if (err) { 
       alert(err); 
       //console.log(err); 
       return; 

      } 
      AuthActions.logUserIn(profile, token); 
      //this.props.login(); 
      this.setState({authenticated:true}); 
     }); 
    } 

    logout() { 
     AuthActions.logUserOut(); 
     //this.props.logout(); 
     this.setState({authenticated:false}); 
    } 

    render() { 
     console.log(this, this.props, this.props.children, this.state); 
     return (
      <div> 
      <div className="container"> 
       <div className="row"> 
        <div className="medium-12 small-12"> 
         <h1>Spin and Win</h1> 

         { !this.state.authenticated ? (
         <div className="medium-12 small-12"> 
          <img src="http://placehold.it/960x360"/> 
         </div> 
         ) : (
          <SlotMachine state={this.state} props={this.props} > 
          </SlotMachine> 
         )} 
        </div> 
       </div> 
       <div className="row"> 
        <div className="medium-12 small-12"> 
         <PlayButton 
          lock={this.lock} 
          state={this.state} 
          login={this.login} 
          logout={this.logout} 
         > 
         </PlayButton> 
        </div> 
       </div> 
      </div> 
      </div> 
     ); 
    } 
} 

//AppComponent.defaultProps = {}; 


export default AppComponent; 

SlotMachine.js

'use strict'; 

import React   from 'react'; 
import Slots   from './Slots'; 
import SpinButton  from './SpinButton'; 
import StatusMessage from './StatusMessage'; 
import Chances from './Chances'; 

const propTypes = { 
    currentUser: React.PropTypes.object 
}; 


// The SlotMachine React class handles the entirety of this very small app. 
class SlotMachine extends React.Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     slotPositions: this.getRandomState(), 
     chancesLeft: 3//this value must be stored in the db 

    }; 
    //console.log(this.state.slotPositions); 
    } 

    // Generates random initial state for slots. 
    componentWillMount() { 

    } 



    //getInitialState() { 
    // return {slotPositions: this.getRandomState()}; 
    //} 

    genSlotValue(){ 
    return Math.floor(Math.random() * 3); 
    } 

    // Generates random landing values for slots using genSlotValue defined at the end of the file 
    getRandomState() { 
    //console.log(genSlotValue(), genSlotValue(), genSlotValue()); 
    return [ 
     genSlotValue(), 
     genSlotValue(), 
     genSlotValue() 
    ]; 
    } 

    useChance() { 
     var noOfChances = this.state.chancesLeft; 
     this.setState({chancesLeft: minusOne(noOfChances)}) 
    } 

    componentWillReceiveProps() { 
    //console.log('componentWillReceiveProps'); 
    //ReactDOM.render(newProps); 
    } 

    handleButtonClick(event) { 
    //console.log(event, this, this.state); 
    this.useChance(); 
    console.log(event, this, this.state, this.props); 
    event.preventDefault(); 
    // Set count to 0 before each button press 
    let count = 0; 
    // Set a random state as the final state of all slots before we start spinning 
    let finalState = this.getRandomState(); 
    // Make sure we start with a fresh state for all slots on each spin 
    let currentState = this.getRandomState(); 
    //console.log(currentState,finalState) 
    // Spinning happens here 
    var makeSpin = function(){ 
     let nextState = currentState; 
     let hasChanged = false; 
     var spinButton = document.getElementById('spin-button'); 

     // Evaluate whether or not slots are on their final destination, spin to nextState if not 
     for(var i = 0; i < 3; i++){ 
     if (count < 9 || currentState[i] != finalState[i]) { 

      nextState[i] = (currentState[i]+1)%3; 
      hasChanged = true; 
      spinButton.setAttribute('disabled', 'disabled'); 
      //spinButton.setTextContent('Spinning!'); 
      spinButton.classList.add('spinning'); 
     } 
     //Re-enable spin button 
     if (count >= 9){ 
      //console.log('count more than 9') 
      spinButton.removeAttribute('disabled'); 
      // spinButton.setTextContent('Spin!'); 
      spinButton.classList.remove('spinning'); 
     } 
     } 

     // Moves reel to the next assigned state if it's not yet on it's final value. 
     this.setState({slotPositions: nextState, isFinal: !hasChanged}) 

     // Stops reel spinning if we've hit the final state's value 
     if(!hasChanged) { 
     return; 
     } 
     currentState = this.state.slotPositions; 
     setTimeout(makeSpin, 100); 
     count++; 
     //console.log(count); 
    }.bind(this); 


    // Actually spin 
    makeSpin(); 
    } 




    render() { 

     // Define winning states 
     let sp = this.state.slotPositions; 
     let isWinning = (sp[0] == sp[1]) && (sp[1] == sp[2]); 

     // Make sure winner, winnerClass, and winnerImage strings are undefined until there's an actual win 
     let winner = ''; 
     let winnerClass = ''; 
     let winnerImage = ''; 

     // Make sure we're only displaying the win state on final slot positions 
     if(isWinning && this.state.isFinal){ 
     winner = [ 
      <h2>You've won John Lewis vouchers!</h2>, 
      <h2>You've won M&amp;S vouchers!</h2>, 
      <h2>You've won Size vouchers!!</h2> 
     ][sp[0]]; 
     winnerClass = [ 
      'coffee', 
      'tea', 
      'espresso' 
     ][sp[0]]; 
     winnerImage = [ 
      <div id='coffee-img' className='tossing win-img'></div>, 
      <div id='tea-img' className='tossing win-img'></div>, 
      <div id='espresso-img' className='tossing win-img'></div> 
     ][sp[0]]; 
    } 

    //console.log(this, this.props, this.props.state.authenticated); 
    return (
     <main className='react-slots'> 
     <div className="medium-12 small-12"> 
      <Chances chancesLeft={this.state.chancesLeft} /> 
      <section className="machine"> 
      <Slots slotPositions={this.state.slotPositions} /> 
      <div className="spin row"> 
       <SpinButton onButtonClick={this.handleButtonClick.bind(this)} /> 
      </div> 
      </section> 
      <section className="win row"> 
      <StatusMessage winner={winner} winnerClass={winnerClass} winnerImage={winnerImage} /> 
      </section> 
     </div> 
     </main> 
    ); 
    } 

} 

// Generates a random slot value. 
function genSlotValue(){ 
    return Math.floor(Math.random() * 3); 
} 

function minusOne(value){ 
    return value - 1; 
} 



SlotMachine.propTypes = propTypes; 


export default SlotMachine; 

PlayButton.js

'use strict'; 

import React, {Component} from 'react'; 
import AuthStore from '../stores/AuthStore'; 

// Creates Spin Button 
class PlayButton extends Component { 

    constructor() { 
     super(); 
     this.state = { 
      authenticated: AuthStore.isAuthenticated() 
     } 
    } 

    render() { 
     //console.log(this, this.props, this.state.authenticated); 
     return (
      <div> 
      {!this.state.authenticated ? (
       <div className="medium-4 small-12"> 
        <button id="play-button" className="play-button" onClick={this.props.login.bind(this)}>Play!</button> 
       </div> 
      ) : (
       <div className="medium-4 small-12"> 
        <button id="play-button" className="play-button" onClick={this.props.logout.bind(this)}>Log out!</button> 
       </div> 
      )} 
      </div> 
     ); 
    } 

} 

export default PlayButton; 

回答

0

首先,你是不是進口AuthStoreAuthActions。另外lock作爲道具傳入AppComponent。你必須確保道具上有鎖定功能,然後才能做this.props.lock。如果可以將代碼重構爲不同的文件,那麼弄清楚發生了什麼會更容易。從教程,this.lock被作爲道具到Header組件過去了,然後this.props.lock.show然後在頭組件調用,在你自己的情況下,你或許應該只是做this.lock.showlogin方法內,而不是this.props.lock.show

+0

感謝您的回覆。我的代碼位於不同的文件中,但我將它粘貼在這裏,以便您可以看到發生了什麼。身份驗證正在工作,但我需要在所有組件上設置狀態並讓它們呈現,目前只有登錄按鈕本身會在其已驗證狀態下重新呈現。其餘的只顯示在referesh認證。我可以告訴你這個項目,如果你有幫助 –

+0

我已經分開了上面的代碼來顯示不同的文件和導入 –

+0

好的,謝謝分割代碼。你想在認證狀態下重新呈現哪些組件,它們何時經過身份驗證和何時未經身份驗證有什麼區別。從代碼中,我可以看到,如果你看App,只有按鈕改變 –

0

你應該包括SlotMachine<SlotMachine state={this.state} props={this.props} />而不是像<SlotMachine state={this.state} props={this.props} ></SlotMachine>因爲後者假定它會有兒童組件/元素在裏面。你也應該重新命名你傳遞給它的道具。這肯定會令人困惑this.props.props

+0

我試過了,但沒有任何區別,組件沒有被重新渲染,我可能必須使用componentWillReceive道具和setState? setState應該觸發組件的重新渲染 –

0

我最終通過配置react-router並以這種方式加載新組件來解決此問題,這迫使新加載的組件檢查身份驗證並顯示適當的內容。

我的應用程序實際上並不需要路由,因爲它嵌入在一個頁面中,我仍然想找到一個沒有路由的解決方案,但現在已經足夠了。

相關問題