重新渲染时保留子组件的状态

时间:2019-09-04 19:58:48

标签: reactjs

我正在构建一个计时器应用,该应用具有按顺序运行的多个计时器。我有一个计时器组件(UnitTimer),该计时器组件基于我的应用状态中的值(numTimers)被循环渲染。每次用户添加新计时器numTimers都会增加通过setState。问题在于每个计时器都在其状态下保存有关其自身的信息(例如应运行多长时间)。当用户添加新计时器时,以前的计时器会奇怪地忘记将其设置为什么时间,但要记住例如其名称。我很困惑,不知道为什么。

应用程序:

class App extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            timer: [],
            timerOn: false,
            timerHasStarted: false,
            appHasBeenReset: false,
            // timerOn:false + timerHasStarted:true = paused
            numTimers: 1,
            activeTimerId: 0,
            totalTime: '',
            timeHasExpired: false,
            succesfullEnding: false

        };
    }


  addNewTimer = () => {
      this.setState(prevState => {
          return { numTimers: prevState.numTimers + 1 };
      });
  };

  removeTimer = () => {
      this.setState(prevState => {
          return { numTimers: prevState.numTimers - 1 };
      });
  };

  renderTimerManagementButtons = () => {
      let buttons = [];
      //allow max 6 timers
      if (this.state.numTimers < 6) {
          buttons.push(
              <Button className="timerManagementButton" key={6} onClick={() => this.addNewTimer()}>+</Button>
          );
      }
      //show remove button as soon as one was added
      if (this.state.numTimers > 1) {
          buttons.push(
              <Button className="timerManagementButton" key={7} onClick={() => this.removeTimer()}>-</Button>
          );
      }

      return buttons;
  };


  renderTimers = () => {
      let timers = [];
      for (let counter = 0; counter < this.state.numTimers; counter++) {
          let key = counter + 1;

          timers.push(
              <UnitTimer key={key}
                  startNextTimer={this.startNextTimer}
                  isActive={key === this.state.activeTimerId}
                  timerIsPaused={key === this.state.activeTimerId && !this.state.timerOn}
                  appHasBeenReset={this.appHasBeenReset}
              />
          );
      }
      return timers;
  };


  startNextTimer = () => {
      let i = this.state.activeTimerId;
      if (this.state.numTimers > 1) {
          this.setState({
              activeTimerId: i + 1
          });
      } else if (this.state.numTimers === this.state.activeTimerId) {
          this.timeExpired();

      } else if (this.state.numTimers === 1) {
          this.timeExpired();
      }
  };

  startTimer = () => {
      this.setState({
          activeTimerId: 1,
          timerOn: true,
          timerHasStarted: true
      });
  };

  resumeTimer = () => {
      this.setState({
          timerOn: true
      });
  };

  pauseTimer = () => {
      this.setState({
          timerOn: false
      });
  };

  resetApp = () => {
      this.setState({
          timerOn: false,
          timerHasStarted: false,
          appHasBeenReset: true,
          activeTimerId: 0
      });
  };

  finishMeeting= () => {
      this.setState({
          timerOn: false,
          timerHasStarted: false,
          appHasBeenReset: true,
          activeTimerId: 0,
          succesfullEnding: true
      });
  };

  timeExpired = () => {
      this.setState({
          timerOn: false,
          timerHasStarted: false,
          appHasBeenReset: true,
          activeTimerId: 0,
          timeHasExpired: true,
          succesfullEnding: false
      });
  };

  printState = () => {
      console.log(this.state);
  };

  renderButtons = () => {
      let buttons = [];

      if (this.state.timerOn === false && this.state.timerHasStarted === false) {
          buttons.push(
              <Button key={1} id="startButton" className="button greenButton" onClick={this.startTimer}>Start Meeting</Button>
          );
      }

      if (this.state.timerOn === true) {
          buttons.push(
              <Button key={2} id="pauseButton" className="button pauseButton" onClick={this.pauseTimer}> </Button>,
              <div className="spacer25px" />,
              <Button key={4} id="finishButton" className="button greenButton" onClick={this.finishMeeting}>Launch Kitties</Button>,
              <div className="spacer25px" />,
              <Button key={3} id="resetButton" className="button textButtonWhite" onClick={this.resetApp}>Reset</Button>
          );
      }

      if (this.state.timerOn === false && this.state.timerHasStarted === true) {
          buttons.push(
              <Button key={5} id="resumeButton" className="button resumeButton" onClick={this.resumeTimer}> </Button>,
              <div className="spacer25px" />,
              <Button key={7} id="finishButton" className="button greenButton" onClick={this.finishMeeting}>Launch Kitties</Button>,
              <div className="spacer25px" />,
              <Button key={6} id="resetButton" className="button textButtonWhite" onClick={this.resetApp}>Reset</Button>
          );
      }


      return buttons;
  }


  renderContent = () => {
      let content = [];
      console.log("I got called");

      if (!this.state.timeHasExpired && !this.state.succesfullEnding) {
          console.log("If statement true");
          content.push(
              <div className="noFlexShrink">
                  <div className="controlsDisplay" />

                  <div className="spacer25px" />

                  {this.renderTimers()}
                  <div className="timerManagementButtonDiv">
                      {this.renderTimerManagementButtons()}
                      <p className="subtilte noMargin">Agenda Items</p>

                  </div>
                  <div className="centerBox">
                      {this.renderButtons()}
                  </div>
              </div>
          );
      } else if (this.state.succesfullEnding && !this.state.timeHasExpired) {
          content.push(
              <div className="noFlexShrink">
                  <h1 className="center white ">Congrats Comrades</h1>
              </div>
          );
      } else if (!this.state.succesfullEnding && this.state.timeHasExpired) {
          content.push(
              <div className="noFlexShrink">
                  <h1 className="center white ">100.000.000 Dead, because of you.</h1>
              </div>
          );
      }
      return content;
  };


  render () {
      return (
      <>
      <div className="appContainer">
        <div className="header">
            <h4 className="white montserrat">KITTEN TIMER</h4>
        </div>

          <div className="centerBox">
              {this.renderContent()}
              <Button className="button greenButton" onClick={this.printState}>Print</Button>,
          </div>
        </div>
      </>
      );
  }
}

export default App;

UnitTimer:

class UnitTimer extends Component {
    componentWillReceiveProps (nextProps) {
        if (nextProps.isActive && !this.props.isActive && !nextProps.timerIsPaused && !this.state.timerOn) {
            this.startTimer();
        } else if (this.props.isActive && nextProps.timerIsPaused) {
            this.stopTimer();
        } else if (this.props.isActive && !nextProps.timerIsPaused && nextProps.isActive && !this.state.timerOn) {
            this.startTimer();
        } else if (!nextProps.isActive) {
            this.resetTimer();
        } else if (nextProps.appHasBeenReset || this.props.appHasBeenReset) {
            this.resetTimer();
        }
    }

  state = {
      timerOn: false,
      timerStart: 0,
      timerTime: 300000,
      timerTitle: ''
  };

  printState = () => {
    console.log(this.state)
    console.log(this.props)
  }

  startTimer = () => {
      this.setState({
          timerOn: true,
          timerTime: this.state.timerTime,
          timerStart: this.state.timerTime
      });
      this.timer = setInterval(() => {
          const newTime = this.state.timerTime - 10;
          if (newTime >= 0) {
              this.setState({
                  timerTime: newTime
              });
          } else {
              clearInterval(this.timer);
              this.setState({ timerOn: false });
              this.props.startNextTimer();
          }
      }, 10);
  };

  stopTimer = () => {
      clearInterval(this.timer);
      this.setState({ timerOn: false });
  };

  handleChange = e => {
      this.setState({ [e.target.name]: e.target.value });
  };

  resetTimer = () => {
      clearInterval(this.timer);
      this.setState({
          timerOn: false,
          timerTime: 300000
      });
  };

  restartTimer = () => {
      clearInterval(this.timer);
      this.setState({
          timerOn: true,
          timerStart: 0
      });
  };

  adjustTimer = input => {
      const { timerTime, timerOn } = this.state;
      if (!timerOn) {
          if (input === 'incMinutes' && timerTime + 60000 < 216000000) {
              this.setState({ timerTime: timerTime + 60000 });
          } else if (input === 'decMinutes' && timerTime - 60000 >= 0) {
              this.setState({ timerTime: timerTime - 60000 });
          }
      }
  };

  jumpTimer = () => {
      this.props.startNextTimer();
  };

  renderButtons = () => {
      let buttons = [];
      if (!this.props.isActive) {
          buttons.push(
              <div key={1} className="timeAdjustmentButtonsDiv">
                  <Button className="incMinutes" key={1} onClick={() => this.adjustTimer('incMinutes')}> </Button>
                  <Button className="decMinutes" key={2} onClick={() => this.adjustTimer('decMinutes')}> </Button>
              </div>
          );
      } else if (this.props.isActive && this.state.timerTime < this.state.timerStart) {
          buttons.push(
              <Button className="button doneButton"key={1} onClick={() => this.jumpTimer()}>Done</Button>,
              //<button key={2} onClick={() => this.restartTimer()}>Restart</button>
          );
      }

      return buttons;
  };

  render () {
      const { timerTime } = this.state;
      let seconds = ('0' + (Math.floor((timerTime / 1000) % 60) % 60)).slice(-2);
      let minutes = ('0' + Math.floor((timerTime / 60000) % 60)).slice(-2);
      //let hours = ('0' + Math.floor((timerTime / 3600000) % 60)).slice(-2);
      let cssClass = (this.props.isActive) ? "unitTimerActive" : "unitTimer";
      return (
          <div className={cssClass} >
              <Input
                  className={(this.props.isActive ? "inputActive" : "inputOnDark")}
                  type="text"
                  placeholder="Agenda Item"
                  name="timerTitle"
                  value={this.state.timerTitle}
                  onChange={this.handleChange}
              />

              <div className={(this.props.isActive ? "timeActive" : "time")} id={(this.state.timerTime < 60000 ? "dangerClose" : " ")}>
                  {minutes} : {seconds}
                  {this.renderButtons()}
              </div>

          </div>
      );
  }
}


export default UnitTimer;


UI:

enter image description here

预先感谢

0 个答案:

没有答案