繁体   English   中英

错误:超过最大更新深度。 当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况

[英]Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate

已经有人问了这个问题,但他们几乎是由相同的原因引起的(原地触发回调,例如<div onClick={this.handleClick()}></div> )。 然而,这并没有发生在我身上,但我得到了同样的错误。

PS 一些 util 函数是在幕后定义的。

// Parent
export default class SearchArea extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: {
                update: '',
                confirmed: '',
                recovered: '',
                deaths: ''
            },
            showDashboard: false
        }
        this.setCountryData = this.setCountryData.bind(this);
        this.showDashboard = this.showDashboard.bind(this);
    }

    setCountryData(data) {
        console.log(data);
        this.setState({
            data: {
                update: data.lastUpdate,
                confirmed: data.confirmed,
                recovered: data.recovered,
                deaths: data.deaths
            }
        });
    }

    showDashboard(toggle) {
        this.setState({ showDashboard: toggle })
    }

    render() {
        return (
            <div>
                <Dropdown onSetCountryData={this.setCountryData} onShowDashboard={this.showDashboard} />
                <Dashboard data={this.state.data} visible={this.state.showDashboard} />
            </div>
        )
    }
}
// Sibling1
class Dropdown extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            countries: [],
            currentCountry: ''
        };
        this.handleClick = this.handleClick.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    handleClick() {
        const showCountryData = Fetch(newFetchCountry).showJSONData;
        showCountryData().then(res => {
            const data = res[0];
            this.passCountryData(data);
        })

        this.passToggleDashboard(true);
    }

    handleChange(e) {
        this.setState({ currentCountry: e.target.value, });
        this.passToggleDashboard(false);
    }

    passCountryData(data) {
        this.props.onSetCountryData(data);
    }

    passToggleDashboard(toggle) {
        this.props.onShowDashboard(toggle);
    }

    componentDidMount() {
        let timer = setTimeout(() => {
            const showCountryList = Fetch(fetchCountryList).showJSONData;
            showCountryList().then(res => {
                const data = res.map(country => country);
                this.setState({ countries: data })
            });
            clearTimeout(timer);
        }, 2000)
    }

    render() {
        return (
            <section className="dropdown-area">
                <div className="dropdown">
                    <label htmlFor="country">Select country:</label>
                    <input list="countries" name="country" id="country" onChange={this.handleChange} />
                    <datalist id="countries" required>
                        {this.state.countries.length ?
                            this.state.countries.map(country => <option key={country.name}>{country.name}</option>) :
                            <option disabled>Loading</option>}
                    </datalist>
                </div>
                <button className="comp" onClick={this.handleClick}>Search</button>

            </section>
        )
    }
}
// Sibling2
class Dashboard extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: {
                update: '',
                confirmed: '',
                recovered: '',
                deaths: ''
            }
        };
    }

    componentDidMount() {
        if (!('data' in this.props)) {
            const showWorldData = Fetch(fetchWorld).showJSONData;
            showWorldData().then(res => {
                const data = res[0];
                this.setState({
                    data: {
                        update: data.lastUpdate,
                        confirmed: data.confirmed,
                        recovered: data.recovered,
                        deaths: data.deaths
                    }
                });
            });
         }
    }

    componentDidUpdate() { // Error here!!!
        if ('data' in this.props) {
            const data = this.props.data;
            this.setState({
                data: {
                    update: data.lastUpdate,
                    confirmed: data.confirmed,
                    recovered: data.recovered,
                    deaths: data.deaths
                }
            });
        }
    }

    render() {
        const visibility = {
            visibility: 'visible' in this.props && !this.props.visible ? 'hidden' : 'visible'
        };
        return (
            <section className="dashboard-area" style={visibility}>
                <span>Last Update: {this.state.data.update || 'Loading...'}</span>
                <div className="dashboards">
                    <DashboardItem num={this.state.data.confirmed} type="Confirmed" />
                    <DashboardItem num={this.state.data.recovered} type="Recovered" />
                    <DashboardItem num={this.state.data.deaths} type="Deaths" />
                </div>
            </section>
        )
    }
}

class DashboardItem extends React.Component {
    render() {
        return (
            <div className="dashboard">{this.props.type}: <br /><span>{this.props.num || 'Loading...'}</span></div>
        )
    }
}

错误出现在Dashboard组件中的componentDidMount()中。 我找不到无限触发重新渲染的位置。

setState 方法会重复更新组件,因为每次'data' in this.props等于true时,您都会调用setState并且调用 setState 默认会更新组件,并且componentDidUpdate将再次检查'data' in this.props等于true

您应该为if语句制定严格的条件

尝试这个

componentDidUpdate(prevProps, prevState) { 
    if ('data' in this.props && this.props.data !== prevProps.data) {
        const data = this.props.data;
        this.setState({
            data: {
                update: data.lastUpdate,
                confirmed: data.confirmed,
                recovered: data.recovered,
                deaths: data.deaths
            }
        });
    }
}

您的问题源于派生的 state: state 它依赖于道具并且是反应中的反模式。

这将告诉你更多关于它的信息:

https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

有一些变通方法,但建议您改用重组数据流。

暂无
暂无

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

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