如何解决此错误,在现有状态转换期间无法更新

问题描述

我收到此错误

在现有状态转换期间(例如在 render)。渲染方法应该是props和 状态。

它发生在这代码中,callback(newdisplayName)

我知道为什么不应该像我的回调那样触发render的原因!我试图解决它,但我感到困惑。 我读了这个cannot-update-during-an-existing-state-transition-error-in-react

但是我无法按照建议使用它,就像我应该使用一些lambda一样:

{(newdisplayName) =>  callback(newdisplayName) }`

但是我有三元运算,所以不一样吗?我也许不必在渲染中进行回调,但是我会更新Redux mapStatetoProps来触发渲染,所以不知道在其他地方做什么

import React from 'react';
import '../../styles/change-name.css';
import { connect } from 'react-redux';
import Dots from 'react-activity/lib/Dots';
import 'react-activity/lib/Dots/Dots.css';
import { changedisplayName } from '../../redux/userData/user.actions';

class ChangeName extends React.Component {
    constructor(props) {
        super(props);
        const { authUser } = this.props;
        this.state = {
            displayName: authUser.displayName ?? '',};
    }

    onSubmit = event => {
        event.preventDefault();
        this.updateUserName();
    };

    onChange = event => {
        this.setState({ [event.target.name]: event.target.value });
    };

    updateUserName() {
        const { displayName } = this.state;
        const { changeUserdisplayName } = this.props;
        changeUserdisplayName(displayName.trim());
    }

    render() {
        const { displayName } = this.state;
        const { callback } = this.props;
        const { authUser,savingdisplayName,newdisplayName,changedisplayNameErr } = this.props;
        const isInvalid = !displayName || !displayName.trim() || displayName.trim().length > 20;
        const isAmended = displayName && displayName.trim() !== authUser.displayName;
        return (
            <div>
                <div className="changename">
                    <form onSubmit={this.onSubmit}>
                        <input
                            name="displayName"
                            value={displayName}
                            onChange={this.onChange}
                            type="text"
                            maxLength="20"
                            placeholder="display name"
                        />
                        <button className="changenamebutton" disabled={isInvalid || !isAmended} type="submit">
                            Confirm
                        </button>
                        {isInvalid && <p className="error">display name must be between 1 and 20 characters in length</p>}
                        {changedisplayNameErr && <p className="error">{changedisplayNameErr.message}</p>}
                        {newdisplayName && <p className="error">New name was saved!</p>}
                        {newdisplayName ? callback(newdisplayName) : ''}
                    </form>
                </div>
                <div>{savingdisplayName ? <Dots /> : null}</div>
            </div>
        );
    }
}

const mapdispatchToProps = dispatch => ({
    changeUserdisplayName: displayName => dispatch(changedisplayName(displayName)),});

const mapStatetoProps = state => {
    return {
        savingdisplayName: state.user.isSavingdisplayName,newdisplayName: state.user.displayName,changedisplayNameErr: state.user.changedisplayNameErrMsg,};
};

export default connect(mapStatetoProps,mapdispatchToProps)(ChangeName);

这是回调的主组件:

import React from 'react';
import '../../styles/profile-page-anonymous.css';
import { compose } from 'recompose';
import { withFirebase } from '../../firebase';
import { AuthUserContext,withAuthorization } from '../../session';
import ChangeName from './ChangeName';
import * as ROLES from '../../constants/roles';

class ProfilePageBase extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            displayName: props.authUser.displayName ?? '',};
        this.nameChange = this.nameChange.bind(this);
    }

    nameChange(displayName) {
        this.setState({
            displayName,});
    }

    render() {
        let userDetails;
        const { authUser } = this.props;
        const { displayName } = this.state;
        if (authUser) {
            userDetails = (
                <div>
                    <div className="profileAnonymous">
                        <table>
                            <tbody>
                                <tr>
                                    <td>display name: </td>
                                    <td>{displayName}</td>
                                </tr>
                                <tr>
                                    <td>User ID: </td>
                                    <td>{authUser.uid}</td>
                                </tr>
                                <tr>
                                    <td>Anonymous: </td>
                                    <td>{authUser.isAnonymous ? 'True' : 'False'}</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                    <div>
                        <h2>Change your display name</h2>
                    </div>
                    <div className="profileBoxChangeNameAnonymous">
                        <ChangeName authUser={authUser} callback={this.nameChange} />
                    </div>
                </div>
            );
        } else {
            userDetails = <p>Unable to get user details. Please try refreshing the page.</p>;
        }

        return <div>{userDetails}</div>;
    }
}

const ProfilePageAnon = props => (
    <AuthUserContext.Consumer>
        {authUser => (
            <div className="profilePageAnonymous">
                <ProfilePageBase {...props} authUser={authUser} />
            </div>
        )}
    </AuthUserContext.Consumer>
);

const condition = authUser => authUser && authUser.roles.includes(ROLES.ANON);

const enhance = compose(withAuthorization(condition),withFirebase);
const ProfilePageAnonymous = enhance(ProfilePageAnon);

export default ProfilePageAnonymous;

更新

重构ProfilePageBase即可解决问题!感谢@DrewReese。我了解了反模式,该模式不以组件状态存储传递的道具。现在,我将ProfilePageBase重构为无状态组件。

ProfilePageBase<AuthUserContext.Consumer>,监听Firestore会在用户对象上发生变化,因此当ChangName将新名称保存到Firestore时,ProfilePageBase会使用AuthUserContext HOC渲染value,即具有新名称用户对象。因此,ChangName现在不需要思考/了解callback

import React from 'react';
import '../../styles/profile-page-anonymous.css';
import { compose } from 'recompose';
import { withFirebase } from '../../firebase';
import { AuthUserContext,withAuthorization } from '../../session';
import ChangeName from './ChangeName';
import * as ROLES from '../../constants/roles';

function ProfilePageBase({ authUser }) {
    return (
        <div>
            {authUser ? (
                <div>
                    <div className="profileAnonymous">
                        <table>
                            <tbody>
                                <tr>
                                    <td>display name: </td>
                                    <td>{authUser.displayName}</td>
                                </tr>
                                <tr>
                                    <td>User ID: </td>
                                    <td>{authUser.uid}</td>
                                </tr>
                                <tr>
                                    <td>Anonymous: </td>
                                    <td>{authUser.isAnonymous ? 'True' : 'False'}</td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                    <div>
                        <h2>Change your display name</h2>
                    </div>
                    <div className="profileBoxChangeNameAnonymous">
                        <ChangeName authUser={authUser} />
                    </div>
                </div>
            ) : (
                <p>Unable to get user details. Please try refreshing the page.</p>
            )}
        </div>
    );
}

const ProfilePageAnon = props => (
    <AuthUserContext.Consumer>
        {authUser => (
            <div className="profilePageAnonymous">
                <ProfilePageBase {...props} authUser={authUser} />
            </div>
        )}
    </AuthUserContext.Consumer>
);

const condition = authUser => authUser && authUser.roles.includes(ROLES.ANON);

const enhance = compose(withAuthorization(condition),withFirebase);
const ProfilePageAnonymous = enhance(ProfilePageAnon);

export default ProfilePageAnonymous;

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)