redux 如何使用自定义绑定获取SyncFusion网格以显示/隐藏微调器

50few1ms  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(105)

我有一个使用自定义绑定的SyncFusion网格,我遇到了两个问题。
1.当最初请求数据填充网格时,它没有显示加载微调器,即使我已经通过一个副作用和一个Redux状态属性(isLoading)设置了加载微调器。通过控制台日志,我可以看到副作用按预期运行,但没有显示微调器。
1.一旦初始数据请求返回并填充网格,微调器就会出现,并且不会停止。我相信这与正在添加的行详细信息模板有关。如果我删除详细信息模板,微调器就不会出现。我已经在外部columnChooser按钮中添加了hideSpnner,单击此按钮后,一切都正常工作。
它不是在我想它出现的时候出现,然后出现而不消失。
一旦我通过了这个初始数据请求并通过外部列选择器按钮强制hideSpinner(),后续数据请求在分页和排序时就可以正常工作,微调器会相应地显示。
不确定这里是否有SyncFusion用户社区,但希望有人能提供帮助。
下面是我的部分:

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { DataStateChangeEventArgs } from "@syncfusion/ej2-react-grids";
import { ServiceRequest } from "./models/ServiceRequest.interface";
import { ServiceRequestResult } from "./models/ServiceRequestResult.interface";
import csmService from "./services/csmMyRequestService";

interface AsyncState {
  isLoading: boolean;
  isSuccess: boolean;
  isError: boolean;
}

interface MyRequestState extends AsyncState {
  result: ServiceRequest[];
  count: number;
}

const initialState: MyRequestState = {
  isLoading: false,
  isSuccess: false,
  isError: false,
  result:[], 
  count: 0
}

export const getMyRequests = createAsyncThunk(
  'csm/getMyRequests',
async (gridCriteria: DataStateChangeEventArgs) => {
  try {
    return await csmService.getMyRequests(gridCriteria);
  } catch (error) {
    console.log('Error: ', error);
  }
});

export const csmMyRequestSlice = createSlice({
  name: 'csmMyRequest',
  initialState,
  reducers: {},
  extraReducers(builder) {
    builder
    .addCase(getMyRequests.pending, (state) => {
      state.isLoading = true;
    })
    .addCase(getMyRequests.fulfilled, (state, action) => {
      
      state.result = action.payload?.myRequests || [];
      state.count = action.payload?.count || 0;

      state.isLoading = false;
      state.isSuccess = true;
    })
    .addCase(getMyRequests.rejected, (state) => {
      
      state.result = [];
      state.count = 0;

      state.isLoading = false;
      state.isError = true;
    })
  },
});

export default csmMyRequestSlice.reducer;

下面是我的组件:

import { FC, useEffect, useRef, useState } from 'react';
import { Internationalization } from '@syncfusion/ej2-base';
import { ColumnDirective, ColumnsDirective, DataStateChangeEventArgs, Grid, GridComponent } from '@syncfusion/ej2-react-grids';
import { Inject, Page, Sort, Filter, FilterSettingsModel, Resize, ColumnChooser, DetailRow } from '@syncfusion/ej2-react-grids';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux/hooks';
import styles from './MyRequests.component.module.scss';
import { getMyRequests } from '../csmMyRequestSlice';
import { IconButton, styled, Tooltip, tooltipClasses, TooltipProps } from '@mui/material';
import ViewColumnIcon from '@mui/icons-material/ViewColumn';
import { ServiceRequestResult } from '../models/ServiceRequestResult.interface';

let instance = new Internationalization();

const MyRequestsComponent: FC = () => {

  const dispatch = useAppDispatch();

  const { isLoading, result, count, isSuccess } = useAppSelector((state) => state.csmMyRequestReducer);

  let initialMyRequests = { result: [], count: 0 };
  const [myRequests, setMyRequests] = useState<ServiceRequestResult>(initialMyRequests);

  const pageSettings = {
    pageSize: 10,
    pageSizes: ["10", "20", "30", "40", "50"]
  };

  const sortSettings = {
    columns: []
  };

  const columnChooserSettings = {
    hideColumns: [
      "Contact",
      "Request Subtype",
      "Reference",
      "Sys. Logged Date",
      "Sys. Closed Date"
    ]
  };

  let myGridInstanceRef: Grid | null;

  const format = (value: Date) => {
    return instance.formatDate(value, { skeleton: 'yMd', type: 'date' });
  };

  const dataBound = () => {
  }

  const dataStateChange = (gridCriteria: DataStateChangeEventArgs) => {

    if (myGridInstanceRef && gridCriteria.action) {
      const requestType = gridCriteria.action.requestType;

      switch (requestType) {
        case 'paging':
        case 'sorting':
          dispatch(getMyRequests(gridCriteria));
          break;
      }
    }
  };

  
  const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
    <Tooltip {...props} classes={{ popper: className }} />
  ))({
    [`& .${tooltipClasses.tooltip}`]: {
      maxWidth: 500,
      fontSize: 13,
      color: 'white',
    },
  });

  function gridDetailTemplate(props: any) {
    return (
      <CustomWidthTooltip title={props.Detail}><p className={`${styles['RequestDetailText']}`}>Detail: {' '}{props.Detail}</p></CustomWidthTooltip>
    );
  }
  let template: any = gridDetailTemplate;

  const columnChooserClick = (event: React.MouseEvent<HTMLElement>) => {
    if (myGridInstanceRef) {
      myGridInstanceRef.hideSpinner(); //Forced hide of spinner here
      myGridInstanceRef.columnChooserModule.openColumnChooser();
    }
  };

  useEffect(() => {
    if (myGridInstanceRef) {
      if (isLoading) {
        console.log('is Loading show spinner'); //Goes through here but spinner doesn't display
        myGridInstanceRef.showSpinner();
      } else {
        console.log('not Loading hide spinner'); //Who knows if it gets hidden as  it never gets displayed
        myGridInstanceRef.hideSpinner();
      }
    }
  }, [isLoading])

  useEffect(() => {
    if (myGridInstanceRef && isSuccess) {
      setMyRequests({ result: result, count: count });
    }
  }, [result, isSuccess])

  useEffect(() => {
    if (myGridInstanceRef) {
      columnChooserSettings.hideColumns.forEach((field) => {
        myGridInstanceRef!.hideColumns(field);
      });

      const gridCriteria = { skip: 0, take: 10 };
      dispatch(getMyRequests(gridCriteria));
    }
  }, [])

  return (
    <div className={`${styles['RequestSection']}`}>
      <legend className={`${styles['RequestLegend']}`}>My Requests:
        <Tooltip title="Show/Hide Columns">
          <IconButton
            className={`${styles['ColumnChooser']}`}
            onClick={columnChooserClick}
            size="small"
          >
            <ViewColumnIcon />
          </IconButton>
        </Tooltip>
      </legend>

      <div className={`${styles['RequestGridContainer']}`}>

        <GridComponent
          ref={(g) => (myGridInstanceRef = g)}
          dataSource={myRequests}
          allowPaging={true} pageSettings={pageSettings}
          allowSorting={true} allowMultiSorting={true} sortSettings={sortSettings}
          allowResizing={true}
          allowReordering={true}
          showColumnChooser={true}
          detailTemplate={template.bind(this)}
          dataBound={dataBound.bind(this)}
          dataStateChange={dataStateChange.bind(this)}
          height='100%'
        >
          <ColumnsDirective>
            <ColumnDirective field='ServiceRequestTag' headerText='Request #' />
            <ColumnDirective field='Caller.Name' headerText='Caller' />
            <ColumnDirective field='Source' />
            <ColumnDirective field='Contact.ContactName' headerText='Contact' />
            <ColumnDirective field='ServiceType.ServiceTypeName' headerText='Service Type' />
            <ColumnDirective field='ServiceRequestType.ServiceRequestTypeName' headerText='Request Type' />
            <ColumnDirective field='ServiceRequestSubtype.ServiceRequestSubtypeName' headerText='Request Subtype' />
            <ColumnDirective field='Poi.Address' headerText='POI Address' />
            <ColumnDirective field='Poi.CityTown' headerText='POI City/Town' />
            <ColumnDirective field='ReferenceNumbers' headerText='Reference' />
            <ColumnDirective field='OwnerName' headerText='Owner' />
            <ColumnDirective field='Status.StatusName' headerText='Status' width='100' />
            <ColumnDirective field='LoggedByName' headerText='Logged By' />
            <ColumnDirective field='LoggedDate' headerText='Logged Date' type='datetime' format='dd MMM yyyy HH:mm' />
            <ColumnDirective field='SystemLoggedDate' headerText='Sys. Logged Date' type='datetime' format='dd MMM yyyy HH:mm' />
            <ColumnDirective field='ClosedByName' headerText='Closed By' />
            <ColumnDirective field='ClosedDate' headerText='Closed Date' type='datetime' format='dd MMM yyyy HH:mm' />
            <ColumnDirective field='SystemClosedDate' headerText='Sys. Closed Date' type='datetime' format='dd MMM yyyy HH:mm' />
            <ColumnDirective field='DueDate' headerText='Due Date' type='datetime' format='dd MMM yyyy HH:mm' />
          </ColumnsDirective>
          <Inject services={[Page, Sort, Resize, ColumnChooser, DetailRow]} />
        </GridComponent>
      </div>
    </div>
  )
}

export default MyRequestsComponent;
kb5ga3dv

kb5ga3dv1#

我认为问题出在myGridInstanceRef变量上。它不是React ref意义上的 true 引用。它在每个渲染周期都被重新声明,所以很可能有同步问题。

let myGridInstanceRef: Grid | null;

这可能应该声明为React引用,以便在不同的渲染周期中保持稳定的引用。

const myGridInstanceRef = React.useRef<Grid | null>();

示例:

const MyRequestsComponent: FC = () => {
  ...

  const myGridInstanceRef = React.useRef<Grid | null>();

  ...

  const dataStateChange = (gridCriteria: DataStateChangeEventArgs) => {

    if (myGridInstanceRef.current && gridCriteria.action) {
      const requestType = gridCriteria.action.requestType;

      switch (requestType) {
        case 'paging':
        case 'sorting':
          dispatch(getMyRequests(gridCriteria));
          break;
      }
    }
  };

  ...

  const columnChooserClick = (event: React.MouseEvent<HTMLElement>) => {
    if (myGridInstanceRef.current) {
      myGridInstanceRef.current.hideSpinner();
      myGridInstanceRef.current.columnChooserModule.openColumnChooser();
    }
  };

  useEffect(() => {
    if (myGridInstanceRef.current) {
      if (isLoading) {
        console.log('is Loading show spinner'); //Goes through here but spinner doesn't display
        myGridInstanceRef.current.showSpinner();
      } else {
        console.log('not Loading hide spinner'); //Who knows if it gets hidden as  it never gets displayed
        myGridInstanceRef.current.hideSpinner();
      }
    }
  }, [isLoading]);

  useEffect(() => {
    if (myGridInstanceRef.current && isSuccess) {
      setMyRequests({ result: result, count: count });
    }
  }, [result, isSuccess]);

  useEffect(() => {
    if (myGridInstanceRef.current) {
      columnChooserSettings.hideColumns.forEach((field) => {
        myGridInstanceRef.current.hideColumns(field);
      });

      const gridCriteria = { skip: 0, take: 10 };
      dispatch(getMyRequests(gridCriteria));
    }
  }, []);

  return (
    <div className={`${styles['RequestSection']}`}>
      <legend className={`${styles['RequestLegend']}`}>My Requests:
        <Tooltip title="Show/Hide Columns">
          <IconButton
            className={`${styles['ColumnChooser']}`}
            onClick={columnChooserClick}
            size="small"
          >
            <ViewColumnIcon />
          </IconButton>
        </Tooltip>
      </legend>

      <div className={`${styles['RequestGridContainer']}`}>
        <GridComponent
          ref={(g) => {
            myGridInstanceRef.current = g;
          }}
          ...
        >
          ...
        </GridComponent>
      </div>
    </div>
  )
}

相关问题