【问题标题】:React Unmounted Component State Update Error反应未安装的组件状态更新错误
【发布时间】:2020-10-14 19:46:52
【问题描述】:

我在反应中有以下组件: PublicProfile.js:

import React, { Component } from 'react';
import axios from 'axios'
import Post from '../posts/Post'
import Navbar from '../Navbar'
import FollowButton from './FollowButton'
import { Avatar, Button, CircularProgress } from '@material-ui/core'

class PublicProfile extends Component {
    constructor(props) {
        super(props);
        this.state = { 
            user: {},
            followers: undefined,
            following: undefined,
            posts: [],
            showFollowers: false,
            showFollows: false,
            curr_id: null
        }
        this.handleFollowerClick = this.handleFollowerClick.bind(this)
        this.handleFollowClick = this.handleFollowClick.bind(this)
    }
    componentDidMount() {
        const { user_id } = this.props.match.params
        axios.get(`http://127.0.0.1:8000/users/${user_id}`)
        .then(res => 
            this.setState({ 
                user: res.data,
                followers: res.data.followers.length, 
                following: res.data.following.length
            }))
        .catch(err => console.log(err))
        axios.get(`http://127.0.0.1:8000/posts/user/${user_id}`)
        .then(res => {
            this.setState({ posts: res.data })
        })   
        .catch(err => console.log(err))
        axios.get('http://127.0.0.1:8000/users/self')
        .then(res => this.setState({curr_id: res.data.id}))
        .catch(err => console.log(err))
    }
    handleFollowerClick(e) {
        e.preventDefault()
        if (this.state.showFollowers === true) {
            this.setState({showFollowers: false})
        } else {
            this.setState({showFollowers: true})
        }
    }
    handleFollowClick(e) {
        e.preventDefault()
        if (this.state.showFollows === true) {
            this.setState({showFollows: false})
        } else {
            this.setState({showFollows: true})
        }
    }
    render() {
        const showFollowers = this.state.showFollowers
        const showFollows = this.state.showFollows
        let followers
        let follows
        let edit
        let fbutton
        if (showFollowers === true) {
            followers = (
                <div>
                    <p>Followed by:</p>
                    <ul>
                        {this.state.user.followers.map(follower => (
                            <li key={follower.id}><a href={`/users/${follower.user.id}`}>{follower.user.username}</a></li>
                        ))}
                    </ul>
                </div>
            )
        }
        if (showFollows === true) {
            follows = (
                <div>
                    <p>Follows:</p>
                    <ul>
                        {this.state.user.following.map(follow => (
                            <li key={follow.id}><a href={`/users/${follow.user.id}`}>{follow.user.username}</a></li>
                        ))}
                    </ul>
                </div>
            )   
        }
        if (this.state.user.id === this.state.curr_id) {
            edit = <Button href='/profile'>Edit My Profile</Button>
        }
        if (this.state.user.id !== this.state.curr_id) {
            fbutton = <FollowButton user={this.state.user} followers_num={this.state.followers} setParentState={state => this.setState(state)} />
        }
        if (this.state.user.id !== undefined) {
            return ( 
                <div style={{background: '#f7f4e9'}}>
                    <Navbar />
                    <div style={{height: '70px'}}></div>
                    <div>
                        <Avatar style={{width: 75, height: 75}} variant='rounded' src={this.state.user.pp} alt={this.state.user.username} />
                        <h1>{this.state.user.username}</h1>
                        <h3>@{this.state.user.username}</h3>
                        <h4>{this.state.posts.length} Post(s)</h4>
                        <p>{this.state.user.bio}</p>
                        <Button style={{marginLeft: '10px'}} disabled={!this.state.following} onClick={this.handleFollowClick}>{this.state.following} Follows</Button>
                        <Button disabled={!this.state.followers} onClick={this.handleFollowerClick}>{this.state.followers} Followers</Button>
                        {followers}
                        {follows}
                    </div>
                    {edit}
                    {fbutton}
                    <div style={{
                        display: 'flex',
                        justifyContent: 'center',
                        alignItems: 'center',
                        flexDirection: 'column'
                    }}>
                        {this.state.posts.map(post => (
                            <Post key={post.id} post={post} />
                        ))}
                    </div>
                    <div style={{height: '15px'}}></div>
                </div>
            )
        } else {
            return (
            <div>
                <Navbar />
                <CircularProgress />
            </div>
            )
        }
    }
}
 

export default PublicProfile

FollowButton.js:

import React, { Component } from 'react';
import axios from 'axios'
import { Button } from '@material-ui/core'

class FollowButton extends Component {
    constructor(props) {
        super(props);
        this.state = { 
            followsUser: null
        }
        this.unfollowClick = this.unfollowClick.bind(this)
        this.followClick = this.followClick.bind(this)
    }
    componentDidMount() {
        if (this.props.user.id !== undefined) {
            axios.get(`http://127.0.0.1:8000/users/check/${this.props.user.id}`)
            .then(res => {
                this.setState({ followsUser: res.data.follows })
            })
            .catch(err => console.log(err)) 
        }
    }
    unfollowClick() {
        axios.delete(`http://127.0.0.1:8000/users/${this.props.user.id}/unfollow/`)
        .then(() => {
            this.setState({ followsUser: false })
            this.props.setParentState({followers: this.props.followers_num - 1})
        })
        .catch(err => console.log(err))
    }
    followClick() {
        axios.post(`http://127.0.0.1:8000/users/${this.props.user.id}/follow/`)
        .then(res => {
            this.setState({ followsUser: true })
            this.props.setParentState({followers: this.props.followers_num + 1})
        })
        .catch(err => console.log(err))
    }
    // user: {
    //     followers: [...this.props.user.followers, res.data.user]
    // }
    render() { 
        let button
        if (this.state.followsUser) {
            button = <Button style={{background: 'blue'}} onClick={this.unfollowClick}>Following</Button>
        } else {
            button = <Button onClick={this.followClick}>Follow</Button>
        }
        return (
            <div style={{marginTop: '20px'}}>
                {button}
            </div> 
            
         );
    }
}

但我收到以下错误:

index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in FollowButton (at PublicProfile.js:93)

我发现这个错误很大程度上是由于卸载组件时未解决的过程,但由于条件,我什至没有在这种情况下渲染组件,但我似乎仍然得到错误。谁能帮我修一下。

【问题讨论】:

  • 第 93 行是哪一行?
  • fbutton = this.setState(state)} />

标签: javascript reactjs


【解决方案1】:

这里是async/await的使用语法:

const unfollowClick = async() => {
         try{
            const res = await axios.delete(`http://127.0.0.1:8000/users/${this.props.user.id}/unfollow/`);
                this.setState({ followsUser: false });
                this.props.setParentState({followers: this.props.followers_num - 1});
            }
          catch(err) { console.log(err)}
        }

【讨论】:

    【解决方案2】:

    卸载组件时,您不会取消 axios 请求。 Axios 接受cancelToken 作为参数,您应该创建一个CancelTokenSource,它提供一个方法cancel,然后在组件卸载时取消Source,这会取消所有挂起的请求。

    【讨论】:

    • 好的,但是我还没有安装组件,所以这怎么可能。
    • 我认为 this.props.setParentState 是您正在更新的父状态,我可以肯定地说 Parent Component 尚未安装,但您正在尝试更新其状态。
    • 好的,但是当呈现跟随按钮而不是编辑按钮时它再次起作用,但是在呈现编辑按钮的情况下我得到错误。
    • 能否提供两个文件的代码,以便我仔细查看代码
    • 尝试使用async/await而不是then,因为它会让axios等待然后更新状态,then不要等待承诺得到实现。它可能会在 then 内一段时间后更新状态,此时组件可能已卸载,否则您的代码对我来说看起来不错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2020-08-28
    • 2023-02-11
    • 2021-12-31
    • 1970-01-01
    • 2020-08-04
    相关资源
    最近更新 更多