Как установить реквизит в состояние в моем случае?

Я изучаю React и создаю приложение для себя, чтобы следить за учебой. Все отлично работает

В моем приложении у меня есть компонент на основе классов, в котором я должен передавать реквизиты в состояние. Однако я понял, что никогда не должен передавать реквизиты в состояние в компоненте, основанном на классе, потому что я мог бы где-нибудь изменить состояние. Но я не знаю, как заставить мой код работать, не передавая реквизиты, как я делаю. Я занимаюсь самообучением, поэтому у меня нет инструктора, поэтому Stackru - мой лучший преподаватель. Спасибо заранее за вашу помощь.

Это мой код. Я изменил его в соответствии с ответом ниже, и теперь он работает нормально, но есть ли что-то, что я должен изменить или избежать в своем коде?

import React from 'react';
import SubjectFrom from './SubjectForm';
import {startSubject} from '../actions/subjectAction';
import {connect} from 'react-redux';

class BeginSubject extends React.Component{
    constructor(props){
        super(props);
        this.state={
            timeRun:0,
            onFinish:'',
            buttonChange:'start',
            timer:null
        }
    }

    componentWillMount(){
        this.setState({timeRun:this.props.subject?this.props.subject.hour*60*60+this.props.subject.minute*60:0,});
    }

    componentWillUnmount(){
        let hour = Math.floor(this.state.timeRun / (60 * 60));
        let minute= Math.floor((this.state.timeRun % (60 * 60)) / 60);
        this.onPause();
        if(this.props.subject){
            this.props.dispatch(startSubject(this.props.subject.id,{hour,minute}))
            console.log(this.props.subject.id)
        }
    }

    onStart=()=>{
        clearInterval(this.timer)
        this.timer = setInterval(()=>{
            let count=this.state.timeRun
            count--
            if(count<0){
                this.setState({onFinish:'well Done'})
                clearInterval(this.timer);
                return;
            }
                let hourleft = Math.floor(count / (60 * 60));
                let minuteleft = Math.floor((count % (60 * 60)) / 60);
                let secondleft = count % 60;

                this.setState({onFinish:`you have ${hourleft} hour ${minuteleft} minute and ${secondleft} second until reaching your goal`});
                this.setState({timeRun:count})
        },1000)
    }

    onPause=()=>{
        clearInterval(this.timer)
        let time = this.props.subject?this.props.subject.hour*60*60+this.props.subject.minute*60:0;
        if(this.state.timeRun<time){
            this.setState({buttonChange:'resume'})
            return;
        }
    }

    onReset=()=>{
        const resetConfirm=confirm('you have not finished, do you want to reset?')
        if(resetConfirm===true){
            clearInterval(this.timer)
            this.setState({timeRun:this.props.subject?this.props.subject.hour*60*60+this.props.subject.minute*60:0,
                            onFinish:'',
                            buttonChange:'start',
                            timer:null})

        }
    }

    render(){
        return(
            <div>
                <p>{this.props.subject?this.props.subject.subjectName:'there is nothing to do for now'}</p>
                <p>{this.props.subject?`you have ${this.props.subject.hour} hour and ${this.props.subject.minute} minute to work`:'there is no time set'}</p>
                <button onClick={this.onStart}>{this.state.buttonChange}</button>
                <button onClick={this.onPause}>pause</button>
                <button onClick={this.onReset}>reset</button>
                <p>{this.state.onFinish}</p>
            </div>
        )
    }
};

const mapStateToProps=(state,props)=>{
    return{
        subject:state.subjects.find((subject)=>subject.id===props.match.params.id)
    };
}
export default connect(mapStateToProps)(BeginSubject)

2 ответа

Решение

Используйте для этого метод жизненного цикла componentWillMount(). установите время, равное 0 для исходного значения. componentWillMount() рассчитает время и установит состояние. он будет выполняться только при первой загрузке компонента. еще использовать componentWillRecieveProps();

Отказ от ответственности: componentWillMount() будет выполняться только один раз, и любые обновления реквизита не будут отражены в дочернем компоненте.

  this.state={
        timeRun:0,
        onFinish:'',
        buttonChange:'start',
        timer:null
    }


componentWillMount(){
     this.setState({timeRun:this.props.subject?this.props.subject.hour*60*60+this.props.subject.minute*60:0,});
}

Помните, что ставить реквизит всегда плохо, даже так, как я предлагал. Лучший способ - отправить вычисленное значение в качестве реквизита дочернему компоненту. и используйте this.props.timeRun. это предотвращает нежелательные циклы и обновления.

Я предлагаю разместить его в методе жизненного цикла componentWillReceiveProps(). Там вы можете управлять, когда вам нужно синхронизировать состояние с реквизитом, а когда нет.

Другие вопросы по тегам