如何在更新行时刷新 Fabric-Ui DetailsList
How to refresh Fabric-Ui DetailsList when updating a row
我正在尝试创建一个 fabric-ui detailsList 组件。该组件应该简单地表示我在数据库中拥有的内容,并且可以为每一行更新特定的列值。要进行更新,每一行都应该有一个 fabric-ui PrimaryButton。
我还在我的服务器中创建了两个 API(GET 和 POST)。 GET 请求将 returns 到反应应用程序将显示的所有资源,并且 POST (在单击特定行的 PrimaryButton 时调用)将在参数中包含该行的 ID 并将更新列的值。
我创建了一个根 component:App,它加载 DetailsList 并调用 GET API 来获取所有资源并显示它们。我还创建了一个子项 component:ResolveButton,它将为根组件中详细信息列表中的每一行调用。
App.tsx:
import * as React from 'react';
import ResolveButton from './ResolveButton';
export interface IDetailsListCustomColumnsExampleState {
sortedItems?: any[];
columns?: IColumn[];
hasError: boolean;
}
export class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
public constructor(props: {}) {
super(props);
this.state = {
columns: [],
hasError:false,
sortedItems: []
};
this._renderItemColumn=this._renderItemColumn.bind(this);
this.changeStatus = this.changeStatus.bind(this);
}
public componentDidCatch() {
// Display fallback UI
this.setState({ hasError: true });
}
public componentDidMount(){
this.fetchResult()
}
public render() {
const { sortedItems, columns } = this.state;
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
else{
return (
<DetailsList
items={sortedItems as any[]}
setKey="set"
columns={columns}
onRenderItemColumn={this._renderItemColumn}
onColumnHeaderClick={this.onColumnClick}
onItemInvoked={this._onItemInvoked}
onColumnHeaderContextMenu={this._onColumnHeaderContextMenu}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
/>
);
}
}
public changeStatus (itemId:React.ReactText){
// TODO : call the POST API to update the status
const { sortedItems } = this.state;
const resolvedKey='Status';
const idKey='Id';
sortedItems!.map(ite => {
if(ite[idKey] === itemId){
ite[resolvedKey] = 3;
}
return ite;
})
this.setState({
sortedItems
});
}
private fetchResult = () =>{
fetch('https://localhost:44329/home')
.then((response) => response.json())
.then(json => this.setState({ columns: _buildColumns(json),
sortedItems: json })).catch((error) =>
{
this.componentDidCatch()
})
}
private onColumnClick = (event: React.MouseEvent<HTMLElement>, column: IColumn): void => {
const { columns } = this.state;
let { sortedItems } = this.state;
let isSortedDescending = column.isSortedDescending;
// If we've sorted this column, flip it.
if (column.isSorted) {
isSortedDescending = !isSortedDescending;
}
// Sort the items.
sortedItems = sortedItems!.concat([]).sort((a, b) => {
const firstValue = a[column.fieldName || ''];
const secondValue = b[column.fieldName || ''];
if (isSortedDescending) {
return firstValue > secondValue ? -1 : 1;
} else {
return firstValue > secondValue ? 1 : -1;
}
});
// Reset the items and columns to match the state.
this.setState({
columns: columns!.map(col => {
col.isSorted = col.key === column.key;
if (col.isSorted) {
col.isSortedDescending = isSortedDescending;
}
return col;
}),
sortedItems
});
};
private _onColumnHeaderContextMenu(column: IColumn | undefined, ev: React.MouseEvent<HTMLElement> | undefined): void {
alert(`column ${column!.key} contextmenu opened.`);
}
private _onItemInvoked(item: any, index: number | undefined): void {
alert(`Item ${item.name} at index ${index} has been invoked.`);
}
private _renderItemColumn(item: any, index: number, column: IColumn) {
const fieldContent = item[column.fieldName || ''];
const crisisColor = {
1: 'Red',
2: 'Orange',
3: 'Yellow',
4: 'Green'
}
const crisis = {
1: 'Crise',
2: 'Haute',
3: 'Moyenne',
4: 'Basse'
}
const statusColor = {
1: 'Black',
2: 'Black',
3: 'Green'
}
const status = {
1: 'Ouvert',
2: 'En cours',
3: 'Résolu'
}
const resolvedKey='Status';
const isResolved = item[resolvedKey]===3;
switch (column.key) {
case 'Status':
return (
<span data-selection-disabled={true} style={{ color: statusColor[fieldContent], height: '100%', display: 'block' }}>
{status[fieldContent]}
</span>
);
case 'Criticity':
return (
<span data-selection-disabled={true} style={{ color: crisisColor[fieldContent], height: '100%', display: 'block' }}>
{crisis[fieldContent]}
</span>
);
case 'Creator':
return(
<div>
<img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
<p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
</div>
);
case 'AssignedTo':
return(
<div>
<img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
<p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
</div>
);
case 'Id':
return(
// tslint:disable-next-line jsx-no-lambda
<ResolveButton disabled={isResolved} uniqueId={fieldContent} changeStatus={ ()=>this.changeStatus(fieldContent)} />
);
default:
return <span>{fieldContent}</span>;
}
}
}
function _buildColumns(json:any[]) {
const columns = buildColumns(json);
return columns;
}
export default App;
ResolveButton.tsx
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import * as React from 'react';
export interface IHandleChange {
changeStatus: ()=>void;
disabled:boolean;
uniqueId:string| number;
}
export class ResolveButton extends React.Component<IHandleChange, {}> {
constructor(props:any) {
super(props);
}
public render(): JSX.Element {
return (
<div>
{
!this.props.disabled &&
<PrimaryButton
data-automation-id="test"
text="Résolu"
onClick={this.props.changeStatus}
allowDisabledFocus={true}
/>
}
</div>
);
}
}
export default ResolveButton;
正如您在我的 App.tsx 中看到的那样,当列键为 "Id" 时,我创建了 ResolveButton 组件。
我的问题是,当单击按钮时,数据将在数据库中更新,但反应应用程序中显示的始终是数据库的旧版本,因此我需要在调用 POST API。
这是一道反应题。
您的 DetailList
使用 sortedItems
来管理其状态。因此,当您点击 ResolveButton
时,您需要更新状态。这没有发生
要解决此问题,ResolveButton
应该公开一个名为 onResolved
的 属性,以便主要组件可以处理更新其状态。
class ResolveButton extends React.Component<IButtonProps, {}> {
async handleClick() {
const response = await fetch('https://localhost:44329/home')
const json = await response.json();
if (this.props.onResolved) {
this.props.onResolved(json);
}
}
}
.
在App
中调用onResolved
更新状态
class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
…
<ResolveButton
disabled={isResolved}
uniqueId={fieldContent}
onResolved={(data) => setState({'sortedItems': data})
/>
…
}
我正在尝试创建一个 fabric-ui detailsList 组件。该组件应该简单地表示我在数据库中拥有的内容,并且可以为每一行更新特定的列值。要进行更新,每一行都应该有一个 fabric-ui PrimaryButton。 我还在我的服务器中创建了两个 API(GET 和 POST)。 GET 请求将 returns 到反应应用程序将显示的所有资源,并且 POST (在单击特定行的 PrimaryButton 时调用)将在参数中包含该行的 ID 并将更新列的值。
我创建了一个根 component:App,它加载 DetailsList 并调用 GET API 来获取所有资源并显示它们。我还创建了一个子项 component:ResolveButton,它将为根组件中详细信息列表中的每一行调用。
App.tsx:
import * as React from 'react';
import ResolveButton from './ResolveButton';
export interface IDetailsListCustomColumnsExampleState {
sortedItems?: any[];
columns?: IColumn[];
hasError: boolean;
}
export class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
public constructor(props: {}) {
super(props);
this.state = {
columns: [],
hasError:false,
sortedItems: []
};
this._renderItemColumn=this._renderItemColumn.bind(this);
this.changeStatus = this.changeStatus.bind(this);
}
public componentDidCatch() {
// Display fallback UI
this.setState({ hasError: true });
}
public componentDidMount(){
this.fetchResult()
}
public render() {
const { sortedItems, columns } = this.state;
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
else{
return (
<DetailsList
items={sortedItems as any[]}
setKey="set"
columns={columns}
onRenderItemColumn={this._renderItemColumn}
onColumnHeaderClick={this.onColumnClick}
onItemInvoked={this._onItemInvoked}
onColumnHeaderContextMenu={this._onColumnHeaderContextMenu}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
/>
);
}
}
public changeStatus (itemId:React.ReactText){
// TODO : call the POST API to update the status
const { sortedItems } = this.state;
const resolvedKey='Status';
const idKey='Id';
sortedItems!.map(ite => {
if(ite[idKey] === itemId){
ite[resolvedKey] = 3;
}
return ite;
})
this.setState({
sortedItems
});
}
private fetchResult = () =>{
fetch('https://localhost:44329/home')
.then((response) => response.json())
.then(json => this.setState({ columns: _buildColumns(json),
sortedItems: json })).catch((error) =>
{
this.componentDidCatch()
})
}
private onColumnClick = (event: React.MouseEvent<HTMLElement>, column: IColumn): void => {
const { columns } = this.state;
let { sortedItems } = this.state;
let isSortedDescending = column.isSortedDescending;
// If we've sorted this column, flip it.
if (column.isSorted) {
isSortedDescending = !isSortedDescending;
}
// Sort the items.
sortedItems = sortedItems!.concat([]).sort((a, b) => {
const firstValue = a[column.fieldName || ''];
const secondValue = b[column.fieldName || ''];
if (isSortedDescending) {
return firstValue > secondValue ? -1 : 1;
} else {
return firstValue > secondValue ? 1 : -1;
}
});
// Reset the items and columns to match the state.
this.setState({
columns: columns!.map(col => {
col.isSorted = col.key === column.key;
if (col.isSorted) {
col.isSortedDescending = isSortedDescending;
}
return col;
}),
sortedItems
});
};
private _onColumnHeaderContextMenu(column: IColumn | undefined, ev: React.MouseEvent<HTMLElement> | undefined): void {
alert(`column ${column!.key} contextmenu opened.`);
}
private _onItemInvoked(item: any, index: number | undefined): void {
alert(`Item ${item.name} at index ${index} has been invoked.`);
}
private _renderItemColumn(item: any, index: number, column: IColumn) {
const fieldContent = item[column.fieldName || ''];
const crisisColor = {
1: 'Red',
2: 'Orange',
3: 'Yellow',
4: 'Green'
}
const crisis = {
1: 'Crise',
2: 'Haute',
3: 'Moyenne',
4: 'Basse'
}
const statusColor = {
1: 'Black',
2: 'Black',
3: 'Green'
}
const status = {
1: 'Ouvert',
2: 'En cours',
3: 'Résolu'
}
const resolvedKey='Status';
const isResolved = item[resolvedKey]===3;
switch (column.key) {
case 'Status':
return (
<span data-selection-disabled={true} style={{ color: statusColor[fieldContent], height: '100%', display: 'block' }}>
{status[fieldContent]}
</span>
);
case 'Criticity':
return (
<span data-selection-disabled={true} style={{ color: crisisColor[fieldContent], height: '100%', display: 'block' }}>
{crisis[fieldContent]}
</span>
);
case 'Creator':
return(
<div>
<img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
<p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
</div>
);
case 'AssignedTo':
return(
<div>
<img src="https://img.mobiscroll.com/demos/BMW_logo.png" width="30px" height="30px" style={{verticalAlign: 'middle', display:'inline' }}/>
<p style={{verticalAlign: 'middle', display:'inline' , paddingLeft:'10px'}}>{fieldContent}</p>
</div>
);
case 'Id':
return(
// tslint:disable-next-line jsx-no-lambda
<ResolveButton disabled={isResolved} uniqueId={fieldContent} changeStatus={ ()=>this.changeStatus(fieldContent)} />
);
default:
return <span>{fieldContent}</span>;
}
}
}
function _buildColumns(json:any[]) {
const columns = buildColumns(json);
return columns;
}
export default App;
ResolveButton.tsx
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import * as React from 'react';
export interface IHandleChange {
changeStatus: ()=>void;
disabled:boolean;
uniqueId:string| number;
}
export class ResolveButton extends React.Component<IHandleChange, {}> {
constructor(props:any) {
super(props);
}
public render(): JSX.Element {
return (
<div>
{
!this.props.disabled &&
<PrimaryButton
data-automation-id="test"
text="Résolu"
onClick={this.props.changeStatus}
allowDisabledFocus={true}
/>
}
</div>
);
}
}
export default ResolveButton;
正如您在我的 App.tsx 中看到的那样,当列键为 "Id" 时,我创建了 ResolveButton 组件。 我的问题是,当单击按钮时,数据将在数据库中更新,但反应应用程序中显示的始终是数据库的旧版本,因此我需要在调用 POST API。
这是一道反应题。
您的 DetailList
使用 sortedItems
来管理其状态。因此,当您点击 ResolveButton
时,您需要更新状态。这没有发生
要解决此问题,ResolveButton
应该公开一个名为 onResolved
的 属性,以便主要组件可以处理更新其状态。
class ResolveButton extends React.Component<IButtonProps, {}> {
async handleClick() {
const response = await fetch('https://localhost:44329/home')
const json = await response.json();
if (this.props.onResolved) {
this.props.onResolved(json);
}
}
}
.
在App
中调用onResolved
更新状态
class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
…
<ResolveButton
disabled={isResolved}
uniqueId={fieldContent}
onResolved={(data) => setState({'sortedItems': data})
/>
…
}