简体   繁体   English

状态更改后,React组件不会重新渲染

[英]React components not re-rendering after state changes

I am learning react and followed this tutorial: https://scotch.io/tutorials/build-a-react-flux-app-with-user-authentication to add authentication to my app. 我正在学习反应,并按照此教程进行操作: https : //scotch.io/tutorials/build-a-react-flux-app-with-user-authentication将身份验证添加到我的应用程序。

Sadly after completing it I realised it only updates the login button and you have to refresh the browser to see the authenticated content. 可悲的是,完成它后,我意识到它只会更新登录按钮,您必须刷新浏览器才能查看经过身份验证的内容。

I've searched all over and tried setting state and props and passing them from parent to children but all to no avail. 我到处搜索,尝试设置状态和道具并将其从父级传递给孩子,但都无济于事。

Below are my three components, any help massively appreciated, I've looked all over the web & studied other React Apps already. 以下是我的三个组成部分,任何得到极大帮助的帮助,我已经遍及整个网络并研究了其他React Apps。

Thanks. 谢谢。

App.js 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 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 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;

First of all, you are not importing AuthStore and AuthActions . 首先,您不会导入AuthStoreAuthActions Also where is the lock being passed as a props into AppComponent . AppComponent lock作为道具传递到AppComponent You have to make sure lock is available in the props before you can do this.props.lock . 您必须先确保道具中的锁可用,然后才能执行this.props.lock It would be easier to figure out what is going on if you can restructure your code into different files. 如果可以将代码重组为其他文件,则更容易弄清楚发生了什么。 From the tutorial, this.lock was passed as a props into the Header Component, and then this.props.lock.show was then called in the Header Component, in your own case you should probably just do this.lock.show inside your login method instead of this.props.lock.show 在本教程中, this.lock作为props被传递到Header Component,然后在Header Component中调用了this.props.lock.show ,在您自己的情况下,您应该只在您的内部执行this.lock.show login方法而不是this.props.lock.show

You should include the SlotMachine like <SlotMachine state={this.state} props={this.props} /> instead of like <SlotMachine state={this.state} props={this.props} ></SlotMachine> because the latter assumes it's gonna have children components/elements inside it. 则应该包括SlotMachine<SlotMachine state={this.state} props={this.props} />而不是像<SlotMachine state={this.state} props={this.props} ></SlotMachine>因为后者假定里面有子组件/元素。 Also you should probably rename the props you are passing into it. 另外,您可能应该重命名传递给它的道具。 It's definitely gonna be confusing to write this.props.props 编写this.props.props肯定会造成混乱

I ended up solving this problem by configuring react-router and loading the new component that way, this forced the newly loaded component to check for the authentication and display the appropriate content. 我最终通过配置react-router并以这种方式加载新组件解决了这个问题,这迫使新加载的组件检查身份验证并显示适当的内容。

My app doesn't actually need routing as it's embedded in a page, I'd still like to find a solution without routing but for now it's enough. 我的应用程序实际上不需要路由,因为它已嵌入页面中,我仍然想找到一种无需路由的解决方案,但现在已经足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM