Reactjs 如何修复此错误在现有状态转换期间无法更新

Reactjs 如何修复此错误在现有状态转换期间无法更新,reactjs,callback,render,ternary,Reactjs,Callback,Render,Ternary,我得到这个错误: 无法在现有状态转换期间更新(例如在 渲染)。渲染方法应该是道具和工具的纯功能 国家 它发生在这段代码的回调(newDisplayName) 我知道为什么渲染不应该像我的回调那样触发!我试图解决它,但我很困惑。 我读了这个 但我不能让它像建议的那样工作,比如我应该使用一些lambda,比如: {(newDisplayName) => callback(newDisplayName) }` 但是我有一个三元运算,所以它是不一样的,对吗?我可能不需要在渲染中进行回调,但我得

我得到这个错误:

无法在现有状态转换期间更新(例如在
渲染
)。渲染方法应该是道具和工具的纯功能 国家

它发生在这段代码的
回调(newDisplayName)

我知道为什么
渲染不应该像我的回调那样触发!我试图解决它,但我很困惑。
我读了这个

但我不能让它像建议的那样工作,比如我应该使用一些lambda,比如:

{(newDisplayName) =>  callback(newDisplayName) }`
但是我有一个三元运算,所以它是不一样的,对吗?我可能不需要在渲染中进行回调,但我得到了触发渲染的Redux
mapstatetops
更新,因此不知道还有什么地方可以这样做

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);

什么是
props.callback
?它有什么作用?渲染方法应该是纯函数,这意味着它们不应该调用任何产生副作用的函数。
props.callback
是对母组件的回调。是的,我知道渲染应该是纯的,这就是为什么我问这个问题如何解决这个问题。在渲染过程中,为了不更新某个状态值,您做了什么?看起来,
callback
可能正在对从redux传入的
newDisplayName
prop执行某些操作。
callback(newDisplayName)
做什么?我看到
ChangeName
被传递
callback={this.nameChange}
,它正在更新父级中的状态。无法从子对象的渲染中执行此操作
newDisplayName
似乎是从redux传递的,因此任何本地组件状态更新都应该在生命周期方法中发生。是否有原因
ProfilePageBase
不订阅
newDisplayName
存储?或者您是否需要
ChangeName
调用回调来更新父级中的状态?巧合的是,在组件状态下存储传递的道具也是一种react反模式。我所做的只是问了一堆问题,让您知道react反模式,其余的都是您自己做的:p顺便说一句,你可以回答/解决你自己的问题。
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;
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;