3

所以基本上我正在开发一个 Ionic/React Typescript 应用程序,当我浏览该应用程序时,会出现两次奇怪的页面转换(参见下面的 gif)

我检查了一下,它不是调用两次的渲染,因为 componentWillMount/didMount/willUnmount 都像推送页面和推送页面一样触发一次。

如您所见,转换总是发生两次,并且在任何地方都找不到解决方案...使用的版本:- Ionic:5.2.1 - React:16.9.0(npm 包)-Typescript 3.6.3(npm 包)


Here is the code for the page with the "Diplomes" Title:
class Diplome extends React.Component<RouteComponentProps> {

  // Function who redirect to the url for edit an situation
  redirectUrlToEditSituation = () => {
    this.props.history.push('/app/edit/diplome/', null);
  }

  render() {
    return (
      <IonPage>
          <IonHeader>
            <IonToolbar>
                <ButtonHambToolBar />
                <ToolBarLogo toolbarName={ToolBarName.DIPLOME}/>
            </IonToolbar>
          </IonHeader>
          <IonContent>
            <FabButtonAction ClickHandler={() => this.redirectUrlToEditSituation()} icon={add}/>
            <GenericList type={ModelType.DIPLOME}/>
          </IonContent>
      </IonPage>
    );
  }
}

export default (Diplome);

这是单击按钮时带有“版本”标题的页面:

class DiplomeEdit extends Component<DiplomeEditProps, {
    dataIsLoad: boolean,
    label_field: string,
    isAnCreate: boolean,
    openModalDelete: boolean,
    isValidation: boolean,
    currentDiplome: any
}>
{

    constructor(props: DiplomeEditProps) {
        super(props);
        this.state = {
            label_field: '',
            isAnCreate: true,
            openModalDelete: false,
            dataIsLoad: false,
            currentDiplome: '',
            isValidation: false,
        };
    }

    async componentWillMount() {
        console.log("component will mount");
        await this.getCurrentDiplomeToUpdate();
    }

    // Function who check if they are param on the url
    // If param exist get the current diplome on the store
    getCurrentDiplomeToUpdate = async () => {
        if (this.props.match.params.idDiplome !== undefined) {

            const diplomes: DiplomeInterface[] = this.props.diplomes;
            if (diplomes.length > 0) {
                const currentDiplomeReceive: DiplomeInterface | undefined = diplomes.find((res: DiplomeInterface) => {
                    return this.props.match.params.idDiplome === res.idDiplome;
                });

                if (currentDiplomeReceive !== undefined) {
                    this.setState({
                        isAnCreate: false,
                        label_field: currentDiplomeReceive.labelDiplome,
                        currentDiplome: currentDiplomeReceive,
                        dataIsLoad: true,
                    });
                }
            }

        } else {
            this.setState({
                isAnCreate: true,
                dataIsLoad: true,
            });
        }
    }

    // Function who render update button
    renderUpdateButton = () => {
        return (
            <div className="contenaire_button_action_situation_edit">
                <Button hidden={this.state.isAnCreate}
                    onClick={() => this.openOrCloseModalDeleteDialog()}
                    className="button_delete_situation">Supprimer</Button>
                <Button
                    onClick={e => this.actionClick()}
                    className="button_action_situation_edit">Enregistrer</Button>
            </div>
        );
    }

    // Function who delete diplome on the databse and on the store
    removeDiplome = async () => {
        await REQUEST.deleteDiplome(this.state.currentDiplome.idDiplome);
        store.dispatch(DELETE_DIPLOME(this.state.currentDiplome.idDiplome));
        this.props.history.replace('/app/diplomes');
    }

    // Function who get the label and id for create new diplome on the databae
    // Reset the state to the default init
    saveDiplome = async () => {
        const obj: DiplomeInterface = {
            idDiplome: Math.random().toString(36).substr(2, 9),
            labelDiplome: this.state.label_field.toLowerCase(),
        };
        this.setState({
            label_field: '',
            isAnCreate: false,
            openModalDelete: false,
        });
        await REQUEST.postDiplome(obj);
        store.dispatch(ADD_DIPLOME(obj));
        //this.props.history.replace('/app/diplomes');
        window.smartAlert("Diplome ajouté avec succès", "success", 5000);
        this.props.history.goBack();
    }

    // Function who update a diplome on the store
    // Need the current diplome
    // Label update
    updateDiplome = async () => {
        const currentDiplomeReceive: DiplomeInterface = this.state.currentDiplome;

        const obj: DiplomeInterface = {
            idDiplome: currentDiplomeReceive.idDiplome,
            labelDiplome: this.state.label_field,
        };

        if (this.props.userConnected.typeAccount === TypeConnect.ADMIN) {
            await REQUEST.updateDiplome(obj);
            store.dispatch(UPDATE_DIPLOME(obj));
            this.props.history.replace('/app/diplomes');
        }
    }

    // Function who checked what action we need
    actionClick = () => {
        if (this.state.isAnCreate) {
            this.saveDiplome();
        } else {
            this.updateDiplome();
        }
    }

    // Function call when input change
    inputChange = (e: any) => {
        this.setState({
            label_field: e.target.value,
        });
    }

    // Function who change the openModalDelete to true
    openOrCloseModalDeleteDialog = () => {
        if (this.props.userConnected.typeAccount === TypeConnect.ADMIN) {
            this.setState({
                openModalDelete: !this.state.openModalDelete,
            });
        }
    }

    render() {

        return (
            <IonPage>
                <IonHeader>
                    <IonToolbar className="task_cat_toolbar">
                        <IonBackButton
                            className="situation_edit_back_button" />
                        <ToolBarLogo toolbarName={ToolBarName.EDIT} />
                    </IonToolbar>
                </IonHeader>

                <IonContent>
                    <div className="contenaire_edit">
                        <div className="contenaire_form_situation">
                            <div className="contenaire_field">
                                <TextField
                                    onChange={e => this.inputChange(e)}
                                    value={this.state.label_field}
                                    className="field_form_situation"
                                    label="Libelle" />
                            </div>

                            <div className="container_task_situation_edit">

                                {!this.state.dataIsLoad && <SpinnerCircular />}

                                {this.renderUpdateButton()}

                                {
                                    this.state.openModalDelete &&
                                    <DialogDelete
                                        actionRemove={() => this.removeDiplome()}
                                        open={this.state.openModalDelete}
                                        actionCloseModal={() => this.openOrCloseModalDeleteDialog()} />
                                }

                            </div>
                        </div>
                    </div>
                </IonContent>

            </IonPage>
        );
    }

}

const mapStateToProps = (state: DiplomeEditProps) => ({
    diplomes: state.diplomes,
    network: state.network,
    role: state.role,
    userConnected: state.userConnected,
});

export default connect(mapStateToProps)(DiplomeEdit);
4

1 回答 1

0

您只是不能将componentWillMount生命周期方法声明为异步。

React 文档中关于UNSAFE_componentWillMount()

Avoid introducing any side-effects or subscriptions in this method.
For those use cases, use componentDidMount() instead.

React 博客“异步渲染更新”(03/2018):

One of the biggest lessons we’ve learned is that some of our legacy component
lifecycles tend to encourage unsafe coding practices. They are:

    componentWillMount
    componentWillReceiveProps
    componentWillUpdate

These lifecycle methods have often been misunderstood and subtly misused; 
furthermore, we anticipate that their potential misuse may be more problematic
with async rendering. Because of this, we will be adding an “UNSAFE_” prefix
to these lifecycles in an upcoming release. (Here, “unsafe” refers not to 
security but instead conveys that code using these lifecycles will be more 
likely to have bugs in future versions of React, especially once async 
rendering is enabled.)

Victoria Fluharty 在该主题上写了有用的帖子componentWillMount() vs componentDidMount()

tl;dr:如果您有异步逻辑,则需要将其移动到(或迁移到更现代的方法,例如使用React 钩子componentDidMount()的功能组件,而不是部分弃用的生命周期方法。

您可以声明componentDidMount()async,但可能会有一些警告:

于 2020-06-22T08:17:03.343 回答