使用 componentDidUpdate 在反应中更新状态
Posted
技术标签:
【中文标题】使用 componentDidUpdate 在反应中更新状态【英文标题】:Updating state in react using componentDidUpdate 【发布时间】:2019-08-29 07:03:33 【问题描述】:我无法在我的代码中更新状态
我的 componentDidUpdate() 出现问题,它在进行 API 调用后没有更新分配状态 更新作业时。当我更新列表中特定分配的到期日期时,它会对服务器进行 API 调用并返回 如果响应成功,则为 true。查看状态更新变化的唯一方法是刷新页面。组件DidUpdate() 陷入无限循环,任何人都可以找出造成这种情况的下划线原因吗?
感谢您的帮助
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】:将数组与!==
比较只会比较数组的引用而不是它们的内容,因此每次更新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);
【讨论】:
以上是关于使用 componentDidUpdate 在反应中更新状态的主要内容,如果未能解决你的问题,请参考以下文章
如何使用钩子清理 componentDidUpdate 中的异步函数