WEBAPP: P8PDataGrid - управление состоянием хука переписано на редьюсер для обеспечения атомарности обновления связанных состояний
This commit is contained in:
parent
3e6afa284d
commit
63751700b4
@ -7,9 +7,10 @@
|
|||||||
//Подключение библиотек
|
//Подключение библиотек
|
||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import { useState, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
|
import { useReducer, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
|
||||||
import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером
|
import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером
|
||||||
import { object2Base64XML } from "../core/utils"; //Вспомогательные функции
|
import { object2Base64XML } from "../core/utils"; //Вспомогательные функции
|
||||||
|
import { DG_AT, INITIAL_STATE, dataGridReducer } from "./p8p_data_grid_reducer"; //Редьюсер состояния
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
//Константы
|
//Константы
|
||||||
@ -38,38 +39,39 @@ const useP8PDataGrid = ({
|
|||||||
initFilters = [],
|
initFilters = [],
|
||||||
initOrders = [],
|
initOrders = [],
|
||||||
storedArgs = {},
|
storedArgs = {},
|
||||||
|
resetPageNumberOnStoredArgsChange = true,
|
||||||
executeStoredArgs = {},
|
executeStoredArgs = {},
|
||||||
|
resetPageNumberOnExecuteStoredArgsChange = true,
|
||||||
allowDataLoad = () => true
|
allowDataLoad = () => true
|
||||||
}) => {
|
}) => {
|
||||||
//Собственное состояние - таблица данных
|
//Подключим редьюсер состояния
|
||||||
const [dataGrid, setDataGrid] = useState({
|
const [state, dispatch] = useReducer(dataGridReducer, INITIAL_STATE({ initFilters, initOrders }));
|
||||||
columnsDef: [],
|
|
||||||
groups: [],
|
|
||||||
rows: [],
|
|
||||||
filters: Array.isArray(initFilters) ? [...initFilters] : [],
|
|
||||||
orders: Array.isArray(initOrders) ? [...initOrders] : [],
|
|
||||||
pageNumber: 1,
|
|
||||||
pagesAlign: null,
|
|
||||||
pagesPosition: null,
|
|
||||||
pagesCount: 0,
|
|
||||||
fixedColumns: 0,
|
|
||||||
fixedHeader: false,
|
|
||||||
morePages: true
|
|
||||||
});
|
|
||||||
|
|
||||||
//Собственное состояние - признак загрузки данных
|
//Установка даных таблицы
|
||||||
const [isDataLoaded, setIsDataLoaded] = useState(false);
|
const setDataGrid = (dataGridData, pageSize, isError) => dispatch({ type: DG_AT.SET_DATA_GRID, payload: { dataGridData, pageSize, isError } });
|
||||||
|
|
||||||
//Собственное состояние - флаг загрузки
|
//Установка фильтра таблицы
|
||||||
const [isLoading, setLoading] = useState(false);
|
const setDataGridFilter = filters => dispatch({ type: DG_AT.SET_DATA_GRID_FILTER, payload: filters });
|
||||||
|
|
||||||
//Собственное состояние - необходимость обновления данных
|
//Установка сортировок таблицы
|
||||||
const [reload, setReload] = useState(true);
|
const setDataGridOrder = orders => dispatch({ type: DG_AT.SET_DATA_GRID_ORDER, payload: orders });
|
||||||
|
|
||||||
//Собственное состояние - дополнительные параметры процедуры
|
//Установка страницы таблицы
|
||||||
|
const setDataGridPageNumber = pageNumber => dispatch({ type: DG_AT.SET_DATA_GRID_PAGE_NUMBER, payload: pageNumber });
|
||||||
|
|
||||||
|
//Установка флага загруженности данных
|
||||||
|
const setIsDataLoaded = isDataLoaded => dispatch({ type: DG_AT.SET_IS_DATA_LOADED, payload: isDataLoaded });
|
||||||
|
|
||||||
|
//Установка флага активности процесса загрузки данных
|
||||||
|
const setIsLoading = isLoading => dispatch({ type: DG_AT.SET_IS_LOADING, payload: isLoading });
|
||||||
|
|
||||||
|
//Установка флага необходимости обновления данных
|
||||||
|
const setReload = (reload, resetPageNumber = false) => dispatch({ type: DG_AT.SET_RELOAD, payload: { reload, resetPageNumber } });
|
||||||
|
|
||||||
|
//Ссылка на актуальные параметры хранимой процедуры
|
||||||
const refStoredArgs = useRef(storedArgs);
|
const refStoredArgs = useRef(storedArgs);
|
||||||
|
|
||||||
//Собственное состояние - дополнительные параметры вызова процедуры
|
//Ссылка на актуальные параметры исполнения хранимой процедуры
|
||||||
const refExecuteStoredArgs = useRef(executeStoredArgs);
|
const refExecuteStoredArgs = useRef(executeStoredArgs);
|
||||||
|
|
||||||
//Признак допустимости обновления данных
|
//Признак допустимости обновления данных
|
||||||
@ -83,52 +85,40 @@ const useP8PDataGrid = ({
|
|||||||
//Загрузка данных таблицы с сервера
|
//Загрузка данных таблицы с сервера
|
||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
//Начинаем загрузку
|
||||||
|
setIsLoading(true);
|
||||||
const data = await executeStored({
|
const data = await executeStored({
|
||||||
stored,
|
stored,
|
||||||
args: {
|
args: {
|
||||||
CFILTERS: { VALUE: object2Base64XML(dataGrid.filters, { arrayNodeName: filtersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
CFILTERS: {
|
||||||
CORDERS: { VALUE: object2Base64XML(dataGrid.orders, { arrayNodeName: ordersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
VALUE: object2Base64XML(state.dataGrid.filters, { arrayNodeName: filtersNodeName }),
|
||||||
NPAGE_NUMBER: dataGrid.pageNumber,
|
SDATA_TYPE: SERV_DATA_TYPE_CLOB
|
||||||
|
},
|
||||||
|
CORDERS: { VALUE: object2Base64XML(state.dataGrid.orders, { arrayNodeName: ordersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
|
||||||
|
NPAGE_NUMBER: state.dataGrid.pageNumber,
|
||||||
NPAGE_SIZE: pageSize,
|
NPAGE_SIZE: pageSize,
|
||||||
NINCLUDE_DEF: reloadDef ? 1 : dataGrid.dataLoaded ? 0 : 1,
|
NINCLUDE_DEF: reloadDef ? 1 : state.isDataLoaded ? 0 : 1,
|
||||||
...refStoredArgs.current
|
...refStoredArgs.current
|
||||||
},
|
},
|
||||||
respArg,
|
respArg,
|
||||||
...refExecuteStoredArgs.current
|
...refExecuteStoredArgs.current
|
||||||
});
|
});
|
||||||
setDataGrid(pv => ({
|
//Устанавливаем полученные данные и признак загрузки данных с учетом возможных ошибок
|
||||||
...pv,
|
setDataGrid(data[contentNodeName], pageSize, isRespErr(data));
|
||||||
...data[contentNodeName],
|
|
||||||
columnsDef: data[contentNodeName].columnsDef ? [...data[contentNodeName].columnsDef] : pv.columnsDef || [],
|
|
||||||
rows:
|
|
||||||
data[contentNodeName].pagesCount > 0 || pv.pageNumber == 1
|
|
||||||
? [...(data[contentNodeName].rows || [])]
|
|
||||||
: [...(pv.rows || []), ...(data[contentNodeName].rows || [])],
|
|
||||||
groups: data[contentNodeName].groups
|
|
||||||
? data[contentNodeName].pagesCount > 0 || pv.pageNumber == 1
|
|
||||||
? [...(data[contentNodeName].groups || [])]
|
|
||||||
: [...(pv.groups || []), ...data[contentNodeName].groups.filter(g => !pv.groups.find(pg => pg.name == g.name))]
|
|
||||||
: [...(pv.groups || [])],
|
|
||||||
morePages: data[contentNodeName].morePages && (data[contentNodeName].rows || []).length >= pageSize
|
|
||||||
}));
|
|
||||||
//Устанавливаем признак загрузки данных с учетом возможных ошибок
|
|
||||||
setIsDataLoaded(!isRespErr(data));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Если произошла ошибка - данные не загружены
|
//Если произошла ошибка - данные не загружены
|
||||||
setIsDataLoaded(false);
|
setIsDataLoaded(false);
|
||||||
} finally {
|
} finally {
|
||||||
//Сбрасываем признаки загрузки и перезагрузки данных
|
//Сбрасываем признаки загрузки и перезагрузки данных
|
||||||
setLoading(false);
|
setIsLoading(false);
|
||||||
setReload(false);
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
SERV_DATA_TYPE_CLOB,
|
SERV_DATA_TYPE_CLOB,
|
||||||
contentNodeName,
|
contentNodeName,
|
||||||
dataGrid.dataLoaded,
|
state.isDataLoaded,
|
||||||
dataGrid.filters,
|
state.dataGrid.filters,
|
||||||
dataGrid.orders,
|
state.dataGrid.orders,
|
||||||
dataGrid.pageNumber,
|
state.dataGrid.pageNumber,
|
||||||
executeStored,
|
executeStored,
|
||||||
filtersNodeName,
|
filtersNodeName,
|
||||||
isRespErr,
|
isRespErr,
|
||||||
@ -140,48 +130,30 @@ const useP8PDataGrid = ({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
//При изменении состояния фильтра
|
//При изменении состояния фильтра
|
||||||
const handleFilterChanged = useCallback(({ filters }) => {
|
const handleFilterChanged = useCallback(({ filters }) => setDataGridFilter(filters), []);
|
||||||
setDataGrid(pv => ({ ...pv, filters: [...filters], pageNumber: 1 }));
|
|
||||||
setReload(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//При изменении состояния сортировки
|
//При изменении состояния сортировки
|
||||||
const handleOrderChanged = useCallback(({ orders }) => {
|
const handleOrderChanged = useCallback(({ orders }) => setDataGridOrder(orders), []);
|
||||||
setDataGrid(pv => ({ ...pv, orders: [...orders], pageNumber: 1 }));
|
|
||||||
setReload(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//При изменении количества отображаемых страниц
|
//При изменении количества отображаемых страниц
|
||||||
const handlePagesCountChanged = useCallback(() => {
|
const handlePagesCountChanged = useCallback(() => setDataGridPageNumber(state.dataGrid.pageNumber + 1), [state.dataGrid.pageNumber]);
|
||||||
setDataGrid(pv => ({ ...pv, pageNumber: pv.pageNumber + 1 }));
|
|
||||||
setReload(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//При изменении страницы отображения
|
//При изменении страницы отображения
|
||||||
const handlePageChange = useCallback(({ page }) => {
|
const handlePageChange = useCallback(({ page }) => setDataGridPageNumber(page), []);
|
||||||
setDataGrid(pv => ({ ...pv, pageNumber: page }));
|
|
||||||
setReload(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
//При необходимости обновления таблицы
|
//При необходимости обновления таблицы
|
||||||
const doReload = useCallback(
|
const doReload = useCallback(
|
||||||
({ returnOnFirstPage = false }) => {
|
({ returnOnFirstPage = false }) => setReload(true, state.dataGrid.pagesCount <= 0 || returnOnFirstPage),
|
||||||
//Если это не страничный вывод или установлен признак возврата на первую страницу
|
[state.dataGrid.pagesCount]
|
||||||
if (dataGrid.pagesCount <= 0 || returnOnFirstPage) {
|
|
||||||
setDataGrid(pv => ({ ...pv, pageNumber: 1 }));
|
|
||||||
}
|
|
||||||
setReload(true);
|
|
||||||
},
|
|
||||||
[dataGrid.pagesCount]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
//Проверка изменений параметров
|
//Проверка изменений параметров
|
||||||
const isArgsChanged = useCallback(
|
const isArgsChanged = useCallback(
|
||||||
(currentArgs, args) => {
|
(currentArgs, args) => {
|
||||||
//Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера)
|
//Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера)
|
||||||
return !isLoading && JSON.stringify(currentArgs) != JSON.stringify(args);
|
return !state.isLoading && JSON.stringify(currentArgs) != JSON.stringify(args);
|
||||||
},
|
},
|
||||||
[isLoading]
|
[state.isLoading]
|
||||||
);
|
);
|
||||||
|
|
||||||
//При изменение дополнительных параметров процедуры
|
//При изменение дополнительных параметров процедуры
|
||||||
@ -191,9 +163,9 @@ const useP8PDataGrid = ({
|
|||||||
//Устанавливаем новые дополнительные параметры
|
//Устанавливаем новые дополнительные параметры
|
||||||
refStoredArgs.current = storedArgs;
|
refStoredArgs.current = storedArgs;
|
||||||
//При изменении дополнительных параметров необходимо перезагрузить данные
|
//При изменении дополнительных параметров необходимо перезагрузить данные
|
||||||
setReload(true);
|
setReload(true, resetPageNumberOnStoredArgsChange);
|
||||||
}
|
}
|
||||||
}, [storedArgs, isArgsChanged]);
|
}, [storedArgs, resetPageNumberOnStoredArgsChange, isArgsChanged]);
|
||||||
|
|
||||||
//При изменение дополнительных параметров вызова процедуры
|
//При изменение дополнительных параметров вызова процедуры
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -202,19 +174,28 @@ const useP8PDataGrid = ({
|
|||||||
//Устанавливаем новые дополнительные параметры
|
//Устанавливаем новые дополнительные параметры
|
||||||
refExecuteStoredArgs.current = executeStoredArgs;
|
refExecuteStoredArgs.current = executeStoredArgs;
|
||||||
//При изменении дополнительных параметров необходимо перезагрузить данные
|
//При изменении дополнительных параметров необходимо перезагрузить данные
|
||||||
setReload(true);
|
setReload(true, resetPageNumberOnExecuteStoredArgsChange);
|
||||||
}
|
}
|
||||||
}, [executeStoredArgs, isArgsChanged]);
|
}, [executeStoredArgs, resetPageNumberOnExecuteStoredArgsChange, isArgsChanged]);
|
||||||
|
|
||||||
//При необходимости обновить данные таблицы
|
//При необходимости обновить данные таблицы
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isAllowDataLoad && reload) {
|
if (isAllowDataLoad && state.reload) {
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
}, [isAllowDataLoad, reload, loadData]);
|
}, [isAllowDataLoad, state.reload, loadData]);
|
||||||
|
|
||||||
//Возвращаем данные таблицы
|
//Возвращаем данные таблицы
|
||||||
return { dataGrid, isDataLoaded, isLoading, handleFilterChanged, handleOrderChanged, handlePagesCountChanged, handlePageChange, doReload };
|
return {
|
||||||
|
dataGrid: state.dataGrid,
|
||||||
|
isDataLoaded: state.isDataLoaded,
|
||||||
|
isLoading: state.isLoading,
|
||||||
|
handleFilterChanged,
|
||||||
|
handleOrderChanged,
|
||||||
|
handlePagesCountChanged,
|
||||||
|
handlePageChange,
|
||||||
|
doReload
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
|||||||
112
app/components/p8p_data_grid_reducer.js
Normal file
112
app/components/p8p_data_grid_reducer.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
Парус 8 - Панели мониторинга
|
||||||
|
Таблица данных - редьюсер состояния
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------
|
||||||
|
//Константы
|
||||||
|
//---------
|
||||||
|
|
||||||
|
//Типы действий
|
||||||
|
const DG_AT = {
|
||||||
|
SET_DATA_GRID: "SET_DATA_GRID", //Установка даных таблицы
|
||||||
|
SET_DATA_GRID_FILTER: "SET_DATA_GRID_FILTER", //Установка фильтра таблицы
|
||||||
|
SET_DATA_GRID_ORDER: "SET_DATA_GRID_ORDER", //Установка сортировок таблицы
|
||||||
|
SET_DATA_GRID_PAGE_NUMBER: "SET_DATA_GRID_PAGE_NUMBER", //Установка страницы таблицы
|
||||||
|
SET_IS_DATA_LOADED: "SET_IS_DATA_LOADED", //Установка флага загруженности данных
|
||||||
|
SET_IS_LOADING: "SET_IS_LOADING", //Установка флага активности процесса загрузки данных
|
||||||
|
SET_RELOAD: "SET_RELOAD" //Установка флага необходимости обновления данных
|
||||||
|
};
|
||||||
|
|
||||||
|
//Состояние приложения по умолчанию
|
||||||
|
const INITIAL_STATE = ({ initFilters, initOrders }) => ({
|
||||||
|
dataGrid: {
|
||||||
|
columnsDef: [],
|
||||||
|
groups: [],
|
||||||
|
rows: [],
|
||||||
|
filters: Array.isArray(initFilters) ? [...initFilters] : [],
|
||||||
|
orders: Array.isArray(initOrders) ? [...initOrders] : [],
|
||||||
|
pageNumber: 1,
|
||||||
|
pagesAlign: null,
|
||||||
|
pagesPosition: null,
|
||||||
|
pagesCount: 0,
|
||||||
|
fixedColumns: 0,
|
||||||
|
fixedHeader: false,
|
||||||
|
morePages: true
|
||||||
|
},
|
||||||
|
isDataLoaded: false,
|
||||||
|
isLoading: false,
|
||||||
|
reload: true
|
||||||
|
});
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
//Тело модуля
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
//Обработчики действий
|
||||||
|
const handlers = {
|
||||||
|
//Установка даных таблицы
|
||||||
|
[DG_AT.SET_DATA_GRID]: (state, { payload }) => {
|
||||||
|
const { dataGridData, pageSize, isError } = payload;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
dataGrid: {
|
||||||
|
...state.dataGrid,
|
||||||
|
...dataGridData,
|
||||||
|
columnsDef: dataGridData.columnsDef ? [...dataGridData.columnsDef] : state.dataGrid.columnsDef || [],
|
||||||
|
rows:
|
||||||
|
dataGridData.pagesCount > 0 || state.dataGrid.pageNumber == 1
|
||||||
|
? [...(dataGridData.rows || [])]
|
||||||
|
: [...(state.dataGrid.rows || []), ...(dataGridData.rows || [])],
|
||||||
|
groups: dataGridData.groups
|
||||||
|
? dataGridData.pagesCount > 0 || state.dataGrid.pageNumber == 1
|
||||||
|
? [...(dataGridData.groups || [])]
|
||||||
|
: [...(state.dataGrid.groups || []), ...dataGridData.groups.filter(g => !state.dataGrid.groups.find(pg => pg.name == g.name))]
|
||||||
|
: [...(state.dataGrid.groups || [])],
|
||||||
|
morePages: dataGridData.morePages && (dataGridData.rows || []).length >= pageSize
|
||||||
|
},
|
||||||
|
isDataLoaded: isError === true ? false : true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
//Установка фильтра таблицы
|
||||||
|
[DG_AT.SET_DATA_GRID_FILTER]: (state, { payload }) => ({
|
||||||
|
...state,
|
||||||
|
dataGrid: { ...state.dataGrid, filters: [...payload], pageNumber: 1 },
|
||||||
|
reload: true
|
||||||
|
}),
|
||||||
|
//Установка сортировок таблицы
|
||||||
|
[DG_AT.SET_DATA_GRID_ORDER]: (state, { payload }) => ({
|
||||||
|
...state,
|
||||||
|
dataGrid: { ...state.dataGrid, orders: [...payload], pageNumber: 1 },
|
||||||
|
reload: true
|
||||||
|
}),
|
||||||
|
//Установка страницы таблицы
|
||||||
|
[DG_AT.SET_DATA_GRID_PAGE_NUMBER]: (state, { payload }) => ({ ...state, dataGrid: { ...state.dataGrid, pageNumber: payload }, reload: true }),
|
||||||
|
//Установка флага загруженности данных
|
||||||
|
[DG_AT.SET_IS_DATA_LOADED]: (state, { payload }) => ({ ...state, isDataLoaded: payload }),
|
||||||
|
//Установка флага активности процесса загрузки данных
|
||||||
|
[DG_AT.SET_IS_LOADING]: (state, { payload }) => ({ ...state, isLoading: payload, reload: payload === false ? false : state.reload }),
|
||||||
|
//Установка флага необходимости обновления данных
|
||||||
|
[DG_AT.SET_RELOAD]: (state, { payload }) => ({
|
||||||
|
...state,
|
||||||
|
reload: payload.reload,
|
||||||
|
...(payload.resetPageNumber ? { dataGrid: { ...state.dataGrid, pageNumber: 1 } } : {})
|
||||||
|
}),
|
||||||
|
//Обработчик по умолчанию
|
||||||
|
DEFAULT: state => state
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
//Интерфейс модуля
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
//Константы
|
||||||
|
export { DG_AT, INITIAL_STATE };
|
||||||
|
|
||||||
|
//Редьюсер состояния
|
||||||
|
export const dataGridReducer = (state, action) => {
|
||||||
|
//Подберём обработчик
|
||||||
|
const handle = handlers[action.type] || handlers.DEFAULT;
|
||||||
|
//Исполним его
|
||||||
|
return handle(state, action);
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user