React报错:无法在未挂载的组件上调用setState
解决React组件中“无法在未挂载的组件上调用setState”错误及数据显示问题
问题描述
开发React组件时遇到报错:无法在未挂载的组件上调用setState,跟随Udemy教程操作但未出现该错误。怀疑是React Router v5与v6版本差异导致,但未找到解决方案。需求是点击用户名或搜索用户名时拉取指定GitHub用户数据,但当前所有this.state调用都无法正常显示结果。
错误原因
- 异步请求时机错误:在
constructor中发起异步请求并调用setState,组件尚未完成挂载就触发状态更新,若组件在请求完成前被卸载,就会触发报错。 - GitHub API路径错误:使用了搜索用户列表的接口
https://api.github.com/search/users/${user},返回的是包含用户数组的对象,而非单个用户数据,导致后续状态处理异常。 - 初始状态与判断逻辑错误:初始
user设为数组[],后续判断this.state.user.login===0逻辑不合理,且数组访问login会引发错误。 - React Router参数传递问题:v6中已移除
withRouter高阶组件,自定义的withRouter可能存在参数传递异常,导致props.params.login无法获取正确值。
修复步骤
- 迁移异步请求到正确生命周期:将请求移至
componentDidMount,确保组件挂载后再发起请求,同时在componentWillUnmount中设置标记,防止组件卸载后更新状态。 - 修正GitHub API接口:改用单个用户查询接口
https://api.github.com/users/${user},直接获取目标用户的完整数据。 - 调整状态初始化与判断逻辑:初始
user设为null,通过判断user是否为空或是否存在错误信息来展示对应内容,同时添加加载状态提示。 - 适配React Router v6(可选):若使用v6,推荐用
useParams钩子,类组件可通过包装为函数组件传递参数,确保login参数正确获取。
完整修复代码
import React, { Component } from "react"; import withRouter from '../withRouter'; import Repose from "./Repose"; class Specific extends Component { constructor(props) { super(props); this.state = { user: null, error: null }; this._isMounted = false; // 标记组件是否挂载 } componentDidMount() { this._isMounted = true; this.fetchUser(this.props.params.login); } componentWillUnmount() { this._isMounted = false; // 组件卸载时更新标记 } fetchUser = async (user) => { try { const apiCall = await fetch(`https://api.github.com/users/${user}`); if (!apiCall.ok) throw new Error('User not found'); const data = await apiCall.json(); // 仅在组件挂载时更新状态 if (this._isMounted) { this.setState({ user: data, error: null }); } } catch (err) { if (this._isMounted) { this.setState({ error: err.message, user: null }); } } } renderData() { const { user, error } = this.state; const { login } = this.props.params; if (error) return <i>No user with given username: {login}</i>; if (!user) return <i>Loading...</i>; return ( <center> <section className="Specific"> <div className="main" id="main"> <div className="container"> <div className="row"> <div className="col-lg-12 col-md-12"> <div className="SUsersData"> <i className="fas fa-heart NotFave"></i> <h4>Name : <i className="bl">{user.name || 'No name'}</i></h4> <img src={user.avatar_url} alt={`${user.login}'s avatar`} /> <h4>followers : <i className="bl">{user.followers}</i></h4> <h4>location : <i className="bl">{user.location || 'No location'}</i></h4> <Repose user={login} /> </div> </div> </div> </div> </div> </section> </center> ); } render() { return ( <React.Fragment> {this.renderData()} </React.Fragment> ); } } export default withRouter(Specific);
内容的提问来源于stack exchange,提问作者genebent
相关产品推荐
相关产品推荐

