React组件道具的更改是否会导致重新渲染?

时间:2020-04-02 00:51:14

标签: javascript reactjs

我正在构建一个简单的计时器作为React的实践。现在,我只是专注于缩短工作时间。当用户在baseSeconds中输入选择内容时,计时器将在该秒停止。

如果您将数字硬编码为prop而不是传递状态,则它会起作用。而且我知道根据我作为测试输出的{this.props.baseSeconds}道具的变化。但是当我将this.state.baseSeconds用作道具时,计时器会继续运行。

“设置”的父项:

const baseMin = [];
for (var i=0; i <= 60; i++) {
    baseMin.push(i);
}

const baseSec = [];
for (var i=0; i <= 60; i++) {
    baseSec.push(i);
}

const displayMinutes = baseMin.map((minute) => 
    <option value={minute}>{minute}</option> 
)

const displaySeconds = baseSec.map((second) => 
    <option value={second}>{second}</option>
)

class Settings extends React.Component {
    constructor(props) {
        super();
        this.state = { 
                baseMinutes: 0, 
                baseSeconds: 0, 
                varMinutes: 0, 
                varSeconds: 0 
            };

        this.updateBaseMin = this.updateBaseMin.bind(this);
        this.updateBaseSec = this.updateBaseSec.bind(this);
        this.updateVarMin = this.updateVarMin.bind(this);
        this.updateVarSec = this.updateVarSec.bind(this);
        this.renderTimer = this.renderTimer.bind(this);
    }


    updateBaseMin(event) {
        this.setState({ baseMinutes: event.target.value });
    }

    updateBaseSec(event) {
        this.setState({ baseSeconds: event.target.value });
    }

    updateVarMin(event) {
        this.setState({ varMinutes: event.target.value });
    }

    updateVarSec(event) {
        this.setState({ varSeconds: event.target.value });
    }

    renderTimer(e) {
        e.preventDefault();
        const { baseMinutes, baseSeconds, varMinutes, varSeconds } = this.state;
            return(
                <Timer baseMinutes={baseMinutes} baseSeconds={baseSeconds} varMinutes={varMinutes} varSeconds={varSeconds}/>
            )
    }




    render() {

        const varMin = [];
        for (var i=0; i <= this.state.baseMinutes; i++) {
            varMin.push(i);
        }
        const displayBaseMin = varMin.map((minute) => 
            <option value={minute}>{minute}</option>
        )

        const varSec = [];
        for (var i=0; i <= this.state.baseSeconds; i++) {
            varSec.push(i);
        }
        const displayBaseSec = varSec.map((second) =>
            <option value={second}>{second}</option>
        )

        const { baseMinutes, baseSeconds, varMinutes, varSeconds } = this.state;


    return (

        <Container>
            Settings
            <form onSubmit={this.renderTimer}>BaseTime
                <select onChange={this.updateBaseMin}>
                    {displayMinutes}
                </select>
                :
                <select onChange={this.updateBaseSec}>
                    {displaySeconds}
                </select>
                VarTime +-
                <select onChange={this.updateVarMin}>
                    {displayBaseMin}
                </select>
                :
                <select onChange={this.updateVarSec}>
                    {displayBaseSec}
                </select>
                <input type="submit" value="Submit" />
            </form>

            <p>{this.state.baseMinutes}, {this.state.baseSeconds}, {this.state.varMinutes}, {this.state.varSeconds}</p>

            <div>{this.renderTimer}</div>
            <Timer baseMinutes={baseMinutes} baseSeconds={this.state.baseSeconds} varMinutes={varMinutes} varSeconds={varSeconds}/>
        </Container >
    )
}
}

export default Settings

计时器的子组件:

class Timer extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
                minutes: 0,
                seconds: 0,
                baseSeconds: this.props.baseSeconds
        }

    this.go = this.go.bind(this);
    this.stop = this.stop.bind(this);
    this.reset = this.reset.bind(this);
    }

    go = () => {

        this.timer = setInterval(() => {

            if ((this.state.seconds) === (this.props.baseSeconds)) {

                clearInterval(this.timer);

            } else {
                this.setState({ seconds: this.state.seconds + 1 })
                console.log(this.state.baseSeconds)
            }
        }, 1000)



    }

    stop = () => {
       clearInterval(this.timer);
    }

    reset = () => {
        this.setState({ minutes: 0, seconds: 0 })
    }


    render() {


        return (
            <div>
                <button onClick={this.go}>start</button>
                <button onClick={this.stop}>stop</button>
                <button onClick={this.reset}>reset</button>
                <p>{this.props.baseMinutes}:{this.props.baseSeconds}</p>

                <p>{this.state.minutes}:{this.state.seconds}</p>
            </div>

        )
    }
}

export default Timer

1 个答案:

答案 0 :(得分:1)

是的,道具更改会导致默认情况下重新渲染。但在您的情况下,在子组件中,初始状态(baseSeconds)是基于不建议使用的道具(this.props.baseSeconds)。构造函数仅运行一次(在组件挂载时),之后不会检测到baseSeconds道具上的任何更新。您可以在渲染内部直接使用道具,而无需使用本地状态。如果必须使用道具更新本地状态,则建议的方法是使用getDerivedStateFromProps生命周期方法。