当前位置: 首页 > 知识库问答 >
问题:

反应错误超出最大更新深度

唐默
2023-03-14

我正在用React做我的前几个实验,在这个组件中,我调用了一个外部API来获取所有NBA玩家的列表,通过作为组件道具接收的teamId过滤它们,最后呈现过滤玩家的标记。

一个需要考虑的问题是,由于我调用了API并获得了一个大列表,所以我将它保持在组件的状态,以便对该组件的新调用将使用该状态,而不是再次调用API。这不是生产代码,我没有API,所以我这样做是因为我收到了“太多请求”消息,因为我一直在尝试这些东西。

无论如何,当我尝试这个代码时,我得到了已经很有名的:

超过了最大更新深度。当组件重复调用组件WillUpdate或组件DidUpdate中的setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环。

我已经研究了标记,我不认为我正在进行任何会导致渲染方法再次触发的方法调用,所以我不知道为什么会发生这种情况。

提前感谢您的任何帮助。

这是有问题的代码:

 class Players extends Component {
    nbaPlayersUrl = "https://someUrl.com";
    state = {
        players: null,
        selectedTeamPlayers: null
    };

    render() {
        if (this.props.teamId === null) return null;

        if (this.state.players !== null) {
            var selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players);
            var markup = this.getMarkup(selectedTeamPlayers);
            this.setState({selectedTeamPlayers: markup});
        } else {
            this.getPlayersList();
        }

        return (
            this.state.selectedTeamPlayers
        );
    }

    getPlayersList() {
        let api = new ExternalApi();
        let that = this;

        api.get(this.nbaPlayersUrl).then(r => {
            r.json().then(result => {
                let players = result.data.map(p => ({
                    id: p.id,
                    firstName: p.first_name,
                    lastName: p.last_name,
                    position: p.position,
                    heightInches: p.height_inches,
                    heightFeet: p.height_feet,
                    weightPounds: p.weight_pounds,
                    teamId: p.team.id
                }));

                that.setState({players: players});
                var selectedTeamPlayers = that.filterPlayersByTeamId(players);
                var markup = that.getMarkup(selectedTeamPlayers);
                that.setState({selectedTeamPlayers: markup});
            });
        });
    }

    filterPlayersByTeamId(players) {
        return players.filter(p => {
            return p.teamId === this.props.teamId;
        });
    }

    getMarkup(players) {
        var result = players.map(p => {
            <li key={p.id}>
                <div>
                    <label htmlFor="firstName">First Name</label> <input type="text" name="firstName" value={p.firstName} readOnly></input>
                </div>
                <div>
                    <label htmlFor="lastName">Last Name</label> <input type="text" name="lastName" value={p.lastName} readOnly></input>
                </div>
                <div>
                    <label htmlFor="position">Position</label> <input type="text" name="position" value={p.position} readOnly></input>
                </div>
            </li>
        });

        return (
            <ul>
                {result}
            </ul>
        );
    }
}

export default Players;

共有3个答案

裴姚石
2023-03-14

事实上,我们不能在render函数中设置state,因为这会产生副作用,所以不能在render函数中调用getPlayersList()。

@Jason Bellomy提到的解决方案是在组件DidMount内部调用getPlayerList来解决此问题的正确方法,因为它在组件插入树后立即调用,因此它是设置用于呈现页面的初始数据的地方。

class Players extends Component {
    nbaPlayersUrl = "https://someUrl.com";
    state = {
        players: null,
        selectedTeamPlayers: null,
    };
    
    componentDidMount(){
     this.getPlayersList();
    }

    render() {
        if (this.props.teamId === null) return null;

        if (this.state.players !== null && this.state.selectedTeamPlayers !== null) {
             return this.getMarkup(selectedTeamPlayers);
        } else {
           return (<span> Loading ... </span>);
        }
    }

    getPlayersList() {
        let api = new ExternalApi();
        let that = this;

        api.get(this.nbaPlayersUrl).then(r => {
            r.json().then(result => {
                let players = result.data.map(p => ({
                    id: p.id,
                    firstName: p.first_name,
                    lastName: p.last_name,
                    position: p.position,
                    heightInches: p.height_inches,
                    heightFeet: p.height_feet,
                    weightPounds: p.weight_pounds,
                    teamId: p.team.id
                }));
               
                 var selectedTeamPlayers = that.filterPlayersByTeamId(players);
             
                that.setState({
                      players: players, 
                      selectedTeamPlayers: selectedTeamPlayers, 
                });
            });
        });
    }

    filterPlayersByTeamId(players) {
        return players.filter(p => {
            return p.teamId === this.props.teamId;
        });
    }

    getMarkup(players) {
        var result = players.map(p => {
            <li key={p.id}>
                <div>
                    <label htmlFor="firstName">First Name</label> <input type="text" name="firstName" value={p.firstName} readOnly></input>
                </div>
                <div>
                    <label htmlFor="lastName">Last Name</label> <input type="text" name="lastName" value={p.lastName} readOnly></input>
                </div>
                <div>
                    <label htmlFor="position">Position</label> <input type="text" name="position" value={p.position} readOnly></input>
                </div>
            </li>
        });

        return (
            <ul>
                {result}
            </ul>
        );
    }
}

export default Players;
单淳
2023-03-14

如果状态和道具改变,组件将重新呈现。在render()函数中:

 if (this.state.players !== null) {
      var selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players);
      var markup = this.getMarkup(selectedTeamPlayers);
      // this.setState({selectedTeamPlayers: 
 }

尝试更改注释行,每次玩家不为空时,组件状态都会更新,因此组件渲染功能将再次运行。

公孙宇
2023-03-14

@Sergio Romero-您不能在渲染函数中设置状态,因为该设置状态将调用新的渲染,而新的渲染将再次设置状态并调用新的呈现,并生成无限循环。数据加载处于渲染和设置状态,这也会创建无限循环。您需要完全重写渲染,使其仅成为状态和道具的视图(它不应该操纵或加载数据)。我想你想要的是:

class Players extends Component {
    nbaPlayersUrl = "https://someUrl.com";
    static propTypes = {
        teamId: PropTypes.number
    };
    static defaultProps = {
        teamId: null
    };
    constructor(props) {
        super(props);
        this.state = {
            players: null
        };
    }
    componentDidMount() {
        this.getPlayerList();
    }
    filterPlayersByTeamId(players, teamId) {
        return players.filter(p => {
            return p.teamId === teamId;
        });
    }
    getPlayersList = () => {
        let api = new ExternalApi();

        api.get(this.nbaPlayersUrl).then(r => {
            r.json().then(result => {
                let players = result.data.map(p => ({
                    id: p.id,
                    firstName: p.first_name,
                    lastName: p.last_name,
                    position: p.position,
                    heightInches: p.height_inches,
                    heightFeet: p.height_feet,
                    weightPounds: p.weight_pounds,
                    teamId: p.team.id
                }));

                this.setState({players});
            });
        });
    };
    render() {
        if (!this.props.teamId || !this.state.players) return null;

        const selectedTeamPlayers = this.filterPlayersByTeamId(this.state.players, this.props.teamId);

        return (
            <ul>
                {
                    selectedTeamPlayers.map(player => {
                        <li key={player.id}>
                            <div>
                                <label htmlFor="firstName">First Name</label><input type="text" name="firstName" value={player.firstName} readOnly></input>
                            </div>
                            <div>
                                <label htmlFor="lastName">Last Name</label><input type="text" name="lastName" value={player.lastName} readOnly></input>
                            </div>
                            <div>
                                <label htmlFor="position">Position</label><input type="text" name="position" value={player.position} readOnly></input>
                            </div>
                        </li>
                    })
                }
            </ul>
        );
    }
}

export default Players;
 类似资料:
  • 我目前收到Maxiumum更新深度错误,不知道为什么。在我的代码中看不到无限循环。 "超过了最大更新深度。当组件在useEffect内部调用setState时,可能会发生这种情况,但useEffect要么没有依赖关系数组,要么其中一个依赖关系在每次渲染时都会发生变化。 此处显示错误 ReactJS组件代码: 下面的代码似乎有错误:超过了最大更新深度。当组件在useEffect中调用setState

  • 早上好,我正在开发一个React应用程序,通过REST API与后端通信。 该应用程序体系结构还使用 React 路由器,并使用服务器提供并存储在中的 JWT 令牌实现身份验证功能。 基本上: 用户连接到应用程序 如果用户未登录,则重定向到登录页面 登录后,它会重定向到带有路径的主页,其中应该显示带有路径的组件和带有路径的组件(如果一个很好地理解React路由器的工作) 在启动应用程序时,用户被正

  • 我有这个错误:错误:超过最大更新深度。当组件重复调用componentWillUpdate或componentDidUpdate内部的setState时,会发生这种情况。React限制嵌套更新的数量,以防止无限循环。 但是我不明白怎么解决!我只是在发布我的代码,对不起… 我的代码:

  • 我正在尝试使用master中的一些函数。js组件。当我运行下面的代码时,我得到错误“error:Maximum update depth exceeded。当组件在componentWillUpdate或componentDidUpdate.React中重复调用setState时,可能会发生这种情况。React限制嵌套更新的数量,以防出现无限循环。” 我在孙子组件中添加按钮时出错了。 如果我注释掉

  • 我试图在参数更改时映射我的 redux 数组。它按预期呈现,但我在控制台中收到此错误。尝试了一些对useeffect的依赖性,但无法修复它。不知道为什么会发生这种情况。感谢您的帮助。 错误; 超过最大更新深度。当组件在useEffect中调用setState时,可能会发生这种情况,但useEfect要么没有依赖项数组,要么在每次渲染时都会更改其中一个依赖项。 我的代码;

  • 问题内容: 我试图在ReactJS中切换组件的状态,但出现错误: 超过最大更新深度。当组件重复调用componentWillUpdate或componentDidUpdate内部的setState时,可能会发生这种情况。React限制了嵌套更新的数量,以防止无限循环。 我在代码中看不到无限循环,有人可以帮忙吗? ReactJS组件代码: 问题答案: 那是因为您在render方法中调用了toggle