使用componentDidUpdate在React中更新状态

时间:2019-04-08 07:25:40

标签: reactjs forms api components state

我无法在代码中更新状态

我的componentDidUpdate()出现问题,无法在进行API调用后更新分配状态 更新作业时。当我更新列表中特定分配的到期日期时,它将对服务器进行API调用并返回 如果响应成功,则为true。在状态中查看更新更改的唯一方法是刷新页面。 componentDidUpdate() 陷入无限循环,谁能找出造成这种情况的原因?

感谢您的帮助

import * as React from 'react';
import './BundleAssignments.less';
import { IBundles, featureAccessApi, IAssignmentsByFirm, IBundleAssignment } from '@afi/tfs';
import { Loader } from '@afi/tfs';

export interface IOwnProps {}

export interface IOwnState {
    loadingBundles: boolean,
    loadingAssignments?: boolean,
    loadingUpdate?: boolean,
    bundles: IBundles[],
    assignments: IAssignmentsByFirm[],
    expirationDate: string,
    bundleId?: number | undefined
}


export class BundleAssignments extends React.Component<IOwnProps, IOwnState> {
    constructor(props: IOwnProps) {
        super(props);
        this.state = {
            loadingBundles: true,
            bundles: [],
            assignments: [],
            expirationDate: "",
            bundleId: undefined
        };
    }

    public componentDidMount() {
        this.loadBundles();
    }

    public componentDidUpdate(prevProps: IOwnProps, prevState: IOwnState)
    {
        if (prevState.assignments !== this.state.assignments && this.state.bundleId !== undefined){

            this.loadBundleAssignments(this.state.bundleId);
        }
    }

    public render() {
        return (
            <div className="bundle-assignments">
                <h1>Bundle assignments</h1>
                {
                    this.state.loadingBundles ? <Loader /> :
                    <>
                        <select onChange={e => this.onChangeSelectedBundle(e)}>
                            <option value="">-- Select a Bundle --</option>
                            {
                                this.state.bundles.map(b => 
                                    <option key={b.id} value={b.id}>{b.name}</option>
                                )
                            }
                        </select>

                        {
                            this.state.assignments != null && this.state.assignments.length > 0 ?
                                (this.state.loadingAssignments || this.state.loadingUpdate) ? <Loader /> :
                                <>
                                    <h1>Assignments</h1>
                                    <div className="download">
                                        <a href={"https://localhost:44301/api/v2/admin/featureBundle/download/" + this.state.bundleId}>Download Excel</a>
                                    </div>
                                    <table className="assignmentsTable">
                                        {
                                            this.state.assignments.map(a => 
                                                <tr key={a.firmRef}>
                                                    <th>
                                                        <span>{a.firmName}</span><br />
                                                        <a href={"admin/teams/firm/" + a.firmRef}>View teams</a>
                                                    </th>
                                                    <td>
                                                    {
                                                        <ul id="entites">
                                                            {
                                                                a.entities.map(e =>
                                                                    <li key={e.entityRef}>
                                                                        <span>{e.entityName}</span>
                                                                    </li>
                                                                )
                                                            }
                                                        </ul>
                                                    }
                                                    </td>
                                                    <td>
                                                    {
                                                        a.entities.map(e =>
                                                            <form key={e.entityRef} onSubmit={(event) => this.handleSubmit(event, e.bundleAssignment.entityRef, e.bundleAssignment.bundleId, e.bundleAssignment.entityTypeId)}>
                                                                <input type="datetime-local" name="expirationDate" defaultValue={e.bundleAssignment.expirationDate}  onChange={this.handleInputChange} />
                                                                <input type="submit" value="Update" />
                                                            </form>         
                                                        )
                                                    }
                                                    </td>
                                                </tr>
                                            )
                                        }
                                    </table>
                                </>
                            : null
                        }
                    </>
                }
            </div>
        )
    }

    private loadBundles = () => {
        featureAccessApi.bundles()
            .then(response => this.loadBundlesSuccess(response.bundles));
    }

    private loadBundlesSuccess = (bundles: IBundles[]) => {
        this.setState({ ...this.state,
            ...{ 
                loadingBundles: false, 
                bundles: bundles
            }
        }) 
    }

    private onChangeSelectedBundle = (e: React.ChangeEvent<HTMLSelectElement>) => {
        const bundleId = Number(e.target.value);
        this.setState({ ...this.state, ...{ loadingAssignments: true, bundleId: bundleId } })
        this.loadBundleAssignments(bundleId);
    }

    private handleSubmit = (e: React.FormEvent, entityRef: number, bundleId: number, entityTypeId: number) => {
        e.preventDefault();
        this.setState({ ...this.state, ...{ loadingUpdate: true }}) 
        this.updateBundleAssignment(entityRef, bundleId, entityTypeId);
    }

    private handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const target = e.target;
        const value = target.value;
        const name = target.name;

        this.setState({ ...this.state, 
            ...{ 
                [name]: value
            } 
        }) 
    }

    private updateBundleAssignment = (entityRef: number, bundleId: number, entityTypeId: number) => {
        const request: IBundleAssignment = {
            entityRef: entityRef,
            bundleId: bundleId,
            entityTypeId: entityTypeId,
            expirationDate: this.state.expirationDate
        };

        featureAccessApi.updateBundleAssignment(request)
            .then(response => this.bundleAssignmentUpdateSuccess());
    }

    private bundleAssignmentUpdateSuccess = () =>
        this.setState({ ...this.state, ...{ loadingUpdate: false }}) 


    private loadBundleAssignments = (bundleId: number) => {
        featureAccessApi.bundleAssignments(bundleId)
            .then(response => this.loadBundleAssignmentsSuccess(response.assignmentsByFirms));
    }

    private loadBundleAssignmentsSuccess = (bundleAssignments: IAssignmentsByFirm[]) => {
        this.setState({ ...this.state,
            ...{ 
                loadingAssignments: false, 
                assignments: bundleAssignments
            }
        }) 
    }
}

1 个答案:

答案 0 :(得分:0)

将数组与!==比较只会比较数组的引用而不是它们的内容,因此,每次更新assignment数组时,loadBundleAssignments都会再次运行。

console.log([1,2] !== [1,2])

您可以改用例如Lodash isEqual检查数组中的所有元素是否彼此匹配。

public componentDidUpdate(prevProps: IOwnProps, prevState: IOwnState) {
  if (
    !_.isEqual(prevState.assignments, this.state.assignments) &&
    this.state.bundleId !== undefined
  ) {
    this.loadBundleAssignments(this.state.bundleId);
  }
}