{"id":335751,"date":"2022-07-15T03:00:07","date_gmt":"2022-07-15T03:00:07","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=335751"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=335751","title":{"rendered":"<span>\u041f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c DataGrid \u043d\u0430 React \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c Boilerplate<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\u00a0\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 \u043c\u043d\u0435 \u0434\u043e\u0432\u0435\u043b\u043e\u0441\u044c \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u043b\u044f \u0432\u0438\u0434\u0435\u043e\u0438\u0433\u0440\u044b \u0441 \u0443\u043a\u043b\u043e\u043d\u043e\u043c \u043d\u0430 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u044b\u0435 \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0430\u043a \u043a\u0430\u043a \u0444\u0438\u043d\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u043b\u043e\u0441\u044c <a href=\"https:\/\/near.org\/grants\/\" rel=\"noopener noreferrer nofollow\">\u0437\u0430 \u0441\u0447\u0435\u0442 \u0433\u0440\u0430\u043d\u0442\u0430<\/a>, \u0431\u044b\u043b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0431\u044e\u0434\u0436\u0435\u0442<\/p>\n<p>\u0412\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044c \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e <strong>\u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0438<\/strong> \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u044b\u0445 \u0444\u043e\u0440\u043c \u0438 \u0444\u043e\u0440\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u0438\u0445 <strong>\u043c\u043e\u0433 \u043c\u0430\u0441\u0441\u043e\u0432\u043e \u043a\u043b\u0435\u043f\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0443\u0440\u043e\u0432\u043d\u044f Junior-<\/strong>. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0445\u043e\u0434\u0430 \u043d\u0430 \u0441\u0430\u043c\u043e\u043e\u043a\u0443\u043f\u0430\u0435\u043c\u043e\u0441\u0442\u044c, \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0435 \u0442\u0440\u0430\u0442\u044f \u0432\u0440\u0435\u043c\u044f \u0438 \u0434\u0435\u043d\u044c\u0433\u0438 \u043d\u0430 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<p>\u0410\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u044c \u0432\u0430\u0436\u043d\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0441 \u0435\u0451 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/Know_your_customer\" rel=\"noopener noreferrer nofollow\">KYC<\/a> \u0438 \u0431\u0430\u043d \u0447\u0438\u0442\u0435\u0440\u043e\u0432. \u041e\u0434\u043d\u0430\u043a\u043e, \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u044d\u0442\u043e \u043d\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0434\u0435\u043d\u044c\u0433\u0438.<\/p>\n<h2>\u0410\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430<\/h2>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0440\u044b\u043d\u043a\u0435, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e<a href=\"https:\/\/devexpress.github.io\/devextreme-reactive\/react\/grid\/demos\/featured\/integrated-data-shaping\/\" rel=\"noopener noreferrer nofollow\"> DevExtreme React Grid<\/a>,  <a href=\"https:\/\/github.com\/bvaughn\/react-virtualized\/blob\/master\/docs\/Grid.md\" rel=\"noopener noreferrer nofollow\">ReactVirtualized Grid<\/a>, <a href=\"https:\/\/www.telerik.com\/kendo-react-ui\/components\/grid\/\" rel=\"noopener noreferrer nofollow\">KendoReact Data Grid<\/a>, <a href=\"https:\/\/mui.com\/x\/react-data-grid\/#commercial-version\" rel=\"noopener noreferrer nofollow\">MUI DataGridPro<\/a>. \u0412\u0441\u0435 \u043e\u043d\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0438\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">import * as React from 'react';  \/\/ import ...  const defaultTheme = createTheme(); const useStylesAntDesign = makeStyles(   (theme) => ({     \/\/ CSS-in-JS   }),   { defaultTheme }, );  const useStyles = makeStyles(   (theme) => ({     \/\/ CSS-in-JS   }),   { defaultTheme }, );  function SettingsPanel(props) {   const { onApply, type, size, theme } = props;   const [sizeState, setSize] = React.useState(size);   const [typeState, setType] = React.useState(type);   const [selectedPaginationValue, setSelectedPaginationValue] = React.useState(-1);   const [activeTheme, setActiveTheme] = React.useState(theme);    const handleSizeChange = React.useCallback((event) => {     setSize(Number(event.target.value));   }, []);    const handleDatasetChange = React.useCallback((event) => {     setType(event.target.value);   }, []);    const handlePaginationChange = React.useCallback((event) => {     setSelectedPaginationValue(event.target.value);   }, []);    const handleThemeChange = React.useCallback((event) => {     setActiveTheme(event.target.value);   }, []);    const handleApplyChanges = React.useCallback(() => {     onApply({       size: sizeState,       type: typeState,       pagesize: selectedPaginationValue,       theme: activeTheme,     });   }, [sizeState, typeState, selectedPaginationValue, activeTheme, onApply]);    return (     &lt;FormGroup className=\"MuiFormGroup-options\" row>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Dataset&lt;\/InputLabel>         &lt;Select value={typeState} onChange={handleDatasetChange}>           &lt;MenuItem value=\"Employee\">Employee&lt;\/MenuItem>           &lt;MenuItem value=\"Commodity\">Commodity&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Rows&lt;\/InputLabel>         &lt;Select value={sizeState} onChange={handleSizeChange}>           &lt;MenuItem value={100}>100&lt;\/MenuItem>           &lt;MenuItem value={1000}>{Number(1000).toLocaleString()}&lt;\/MenuItem>           &lt;MenuItem value={10000}>{Number(10000).toLocaleString()}&lt;\/MenuItem>           &lt;MenuItem value={100000}>{Number(100000).toLocaleString()}&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Page Size&lt;\/InputLabel>         &lt;Select value={selectedPaginationValue} onChange={handlePaginationChange}>           &lt;MenuItem value={-1}>off&lt;\/MenuItem>           &lt;MenuItem value={0}>auto&lt;\/MenuItem>           &lt;MenuItem value={25}>25&lt;\/MenuItem>           &lt;MenuItem value={100}>100&lt;\/MenuItem>           &lt;MenuItem value={1000}>{Number(1000).toLocaleString()}&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Theme&lt;\/InputLabel>         &lt;Select value={activeTheme} onChange={handleThemeChange}>           &lt;MenuItem value=\"default\">Default Theme&lt;\/MenuItem>           &lt;MenuItem value=\"ant\">Ant Design&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;Button         size=\"small\"         variant=\"outlined\"         color=\"primary\"         onClick={handleApplyChanges}       >         &lt;KeyboardArrowRightIcon fontSize=\"small\" \/> Apply       &lt;\/Button>     &lt;\/FormGroup>   ); }  SettingsPanel.propTypes = {   onApply: PropTypes.func.isRequired,   size: PropTypes.number.isRequired,   theme: PropTypes.oneOf(['ant', 'default']).isRequired,   type: PropTypes.oneOf(['Commodity', 'Employee']).isRequired, };  export default function FullFeaturedDemo() {   const classes = useStyles();   const antDesignClasses = useStylesAntDesign();   const [isAntDesign, setIsAntDesign] = React.useState(false);   const [type, setType] = React.useState('Commodity');   const [size, setSize] = React.useState(100);   const { loading, data, setRowLength, loadNewData } = useDemoData({     dataSet: type,     rowLength: size,     maxColumns: 40,     editable: true,   });    const [pagination, setPagination] = React.useState({     pagination: false,     autoPageSize: false,     pageSize: undefined,   });    const getActiveTheme = () => {     return isAntDesign ? 'ant' : 'default';   };    const handleApplyClick = (settings) => {     if (size !== settings.size) {       setSize(settings.size);     }      if (type !== settings.type) {       setType(settings.type);     }      if (getActiveTheme() !== settings.theme) {       setIsAntDesign(!isAntDesign);     }      if (size !== settings.size || type !== settings.type) {       setRowLength(settings.size);       loadNewData();     }      const newPaginationSettings = {       pagination: settings.pagesize !== -1,       autoPageSize: settings.pagesize === 0,       pageSize: settings.pagesize > 0 ? settings.pagesize : undefined,     };      setPagination((currentPaginationSettings) => {       if (         currentPaginationSettings.pagination === newPaginationSettings.pagination &amp;&amp;         currentPaginationSettings.autoPageSize ===           newPaginationSettings.autoPageSize &amp;&amp;         currentPaginationSettings.pageSize === newPaginationSettings.pageSize       ) {         return currentPaginationSettings;       }       return newPaginationSettings;     });   };    return (     &lt;div className={classes.root}>       &lt;SettingsPanel         onApply={handleApplyClick}         size={size}         type={type}         theme={getActiveTheme()}       \/>       &lt;DataGridPro         className={isAntDesign ? antDesignClasses.root : undefined}         {...data}         components={{           Toolbar: GridToolbar,         }}         loading={loading}         checkboxSelection         disableSelectionOnClick         {...pagination}       \/>     &lt;\/div>   ); } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 DataGridPro <a href=\"https:\/\/codesandbox.io\/s\/nasty-mui-datagridpro-sample-uchw3m\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0436\u043d\u043e \u0442\u0443\u0442<\/a>. \u041f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e \u0432\u0435\u0434\u0435\u0442 \u043a \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u0430\u0434\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043e\u043a, \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438 \u043b\u044f\u0436\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u0435\u0440\u0442\u0432\u044b\u043c \u0433\u0440\u0443\u0437\u043e\u043c legacy<\/p>\n<h2>\u0422\u0435\u0437\u0438\u0441\u044b \u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0445 \u043a\u043e\u0434\u0430 \u0432\u044b\u0448\u0435<\/h2>\n<ol>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 <code>useState<\/code>, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 <code>type<\/code>, <code>size<\/code> \u0438  <code>pagination<\/code> \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433, \u043a\u043e\u0433\u0434\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c, \u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e  \u043d\u0435 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b. \u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e (\u0441\u043c \u043a\u043d\u043e\u043f\u043a\u0443 <em>Apply<\/em>)?<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>SettingsPanel <\/code>\u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u0421\u043f\u043e\u0440\u043d\u043e, \u043d\u043e \u043f\u043e \u043c\u043e\u0435\u043c\u0443, \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u0435\u0440\u043d\u0435\u0442 <code>JSX.Element<\/code>, \u0430 \u043d\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/p>\n<\/li>\n<li>\n<p>\u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 backend? \u041a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 status-500, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443?<\/p>\n<\/li>\n<\/ol>\n<h2>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/h2>\n<ol>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0447\u0438\u0441\u0442\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 <code>filterData<\/code>, <code>limit<\/code>, <code>offset<\/code> \u0438 \u0442.\u0434., \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043b\u0438\u0431\u043e \u043c\u0430\u0441\u0441\u0438\u0432, \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u043c\u0438\u0441 \u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0444\u0438\u0440\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 <code>SettingsPanel<\/code>. \u0418\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u043f\u0441\u044b, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (<em>\u043f\u0443\u043d\u043a\u0442 1<\/em>) \u0432\u043a\u043b\u044e\u0447\u0438\u0442 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442 \u0435\u0433\u043e \u0432 \u0431\u043b\u043e\u043a\u0435 <code>finally<\/code> \u0438, \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u043e\u043f\u043e\u0432\u0435\u0441\u0442\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e status-500<\/p>\n<\/li>\n<\/ol>\n<h2>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e<\/h2>\n<p>\u041d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043a\u043d\u043e\u043f\u043e\u043a \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u0438\u0433\u043b\u0430\u0441\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e? \u041d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043b\u043e\u043d\u043a\u0443 &#171;\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f&#187; \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 &#171;\u041f\u0440\u0438\u0433\u043b\u0430\u0441\u0438\u0442\u044c&#187;. \u041e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0434\u043b\u044f \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/30d\/cbf\/99e\/30dcbf99e26fae52c3e5f74dcc4426ce.png\" alt=\"MUI DataGridPro\" title=\"MUI DataGridPro\" width=\"964\" height=\"610\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/30d\/cbf\/99e\/30dcbf99e26fae52c3e5f74dcc4426ce.png\"\/><figcaption>MUI DataGridPro<\/figcaption><\/figure>\n<p>\u0410 \u0435\u0449\u0451, \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u0430\u043c \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. <\/p>\n<h3>\u0427\u0438\u0441\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430 \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0433\u0440\u0438\u0434\u0430, \u044f \u0431\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u043f\u0441\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u0447\u0438\u0441\u0442\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u043c<\/p>\n<pre><code class=\"typescript\">import { List } from 'react-declarative';  type RowId = string | number;  interface IRowData {   id: RowId; }  type HandlerPagination = {   limit: number;   offset: number; };  type HandlerSortModel&lt;RowData extends IRowData = any> = {   field: keyof RowData;   sort: 'asc' | 'desc'; }[];  type HandlerChips&lt;RowData extends IRowData = any> =    Record&lt;keyof RowData, boolean>;  type HandlerResult&lt;RowData extends IRowData = IAnything> = {   rows: RowData[];   total: number | null; };  type Handler&lt;FilterData = any, RowData extends IRowData = any> = (   filterData: FilterData,   pagination: ListHandlerPagination,   sort: ListHandlerSortModel&lt;RowData>,   chips: ListHandlerChips&lt;RowData>,   search: string, ) => Promise&lt;HandlerResult&lt;RowData>> | HandlerResult&lt;RowData>;  const handler: Handler = (filterData, pagination, sort, chips, search) => { ... };  ...  &lt;List   handler={handler}   ... \/><\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>handler<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u044f\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432<\/p>\n<ol>\n<li>\n<p><strong>filterData<\/strong> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 SettingsPanel, \u0443\u0441\u043b\u043e\u0432\u043d\u043e. \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 ComboBox, \u0441\u043b\u0430\u0439\u0434\u0435\u0440\u0430\u043c\u0438 \u0438 \u0442.\u0434.<\/p>\n<\/li>\n<li>\n<p><strong>pagination<\/strong> &#8212; \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0434\u0432\u0443\u043c\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: <code>limit<\/code> \u0438 <code>offset<\/code>\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438. \u041f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0431\u0435\u043a \u0434\u043b\u044f \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 <code>rows.slice(offset, limit + offset)<\/code><\/p>\n<\/li>\n<li>\n<p><strong>sort<\/strong> &#8212; \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430\u043c\u0438 \u043a\u043e\u043b\u043e\u043d\u043e\u043a. \u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 <code>asc<\/code> (ascending &#8212; \u043f\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u043d\u0438\u044e) \u0438\u043b\u0438 <code>desc<\/code> (descending &#8212; \u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e)<\/p>\n<\/li>\n<li>\n<p><strong>chips<\/strong> &#8212; \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0431\u0443\u043b\u0435\u0432\u0441\u043a\u0438\u043c\u0438 \u0444\u043b\u0430\u0433\u0430\u043c\u0438 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0440\u0435\u0434\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u043d\u044b\u0445 \u043a\u0430\u043a \u0441\u0430\u043c\u043e\u0437\u0430\u043d\u044f\u0442\u044b\u0445<\/p>\n<\/li>\n<li>\n<p><strong>search &#8212; <\/strong>\u0441\u0442\u0440\u043e\u043a\u0430 \u0441 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u043c, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0440\u0430\u0441\u043f\u0430\u0440\u0441\u0438\u0442\u044c \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u044f\u0437\u044b\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043a\u0430\u043a \u0434\u0435\u043b\u0430\u0435\u0442 \u0433\u0443\u0433\u043b<\/p>\n<\/li>\n<\/ol>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044e handler \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Factory_method_pattern\" rel=\"noopener noreferrer nofollow\">Factory<\/a>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0432 \u0445\u0443\u043a<\/p>\n<pre><code class=\"typescript\">import mock from '.\/person_list.json';  ...  const handler = useArrayPaginator(mock);<\/code><\/pre>\n<p>\u0425\u0443\u043a <code>useArrayPaginator<\/code> \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430 \u043b\u0435\u0442\u0443 \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043f\u044f\u0442\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 <code>handler<\/code>. \u041a \u0441\u043b\u043e\u0432\u0443, \u0442\u0430\u043a \u0436\u0435 \u043d\u0430 \u0432\u0445\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u043c\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0435\u0440\u043d\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u0435\u0437 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043e\u043a, \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438 \u0438 \u0442.\u0434.<\/p>\n<pre><code class=\"typescript\">import ...  const EMPTY_RESPONSE = {     rows: [],     total: null, };  type ArrayPaginatorHandler&lt;FilterData = any, RowData extends IRowData = any> =   RowData[] | ((     data: FilterData,     pagination: ListHandlerPagination,     sort: ListHandlerSortModel&lt;RowData>,     chips: ListHandlerChips&lt;RowData>,     search: string,   ) => Promise&lt;ListHandlerResult&lt;RowData>> | ListHandlerResult&lt;RowData>);  export interface IArrayPaginatorParams&lt;   FilterData = any,   RowData extends IRowData = any > {     filterHandler?: (rows: RowData[], filterData: FilterData) => RowData[];     chipsHandler?: (rows: RowData[], chips: HandlerChips&lt;RowData>) => RowData[];     sortHandler?: (rows: RowData[], sort: HandlerSortModel&lt;RowData>) => RowData[];     paginationHandler?: (rows: RowData[], pagination: HandlerPagination) => RowData[];     searchHandler?: (rows: RowData[], search: string) => RowData[];     withPagination?: boolean;     withFilters?: boolean;     withChips?: boolean;     withSort?: boolean;     withTotal?: boolean;     withSearch?: boolean;     onError?: (e: Error) => void;     onLoadStart?: () => void;     onLoadEnd?: (isOk: boolean) => void; }  export const useArrayPaginator = &lt;   FilterData = any,   RowData extends IRowData = any >(   rowsHandler: ArrayPaginatorHandler&lt;FilterData, RowData>, {     filterHandler = (rows, filterData) => {         Object.entries(filterData).forEach(([key, value]) => {             if (value) {                 const templateValue = String(value).toLocaleLowerCase();                 rows = rows.filter((row) => {                     const rowValue = String(row[key as keyof RowData])                       .toLowerCase();                     return rowValue.includes(templateValue);                 });             }         });         return rows;     },     chipsHandler = (rows, chips) => {         if (!Object.values(chips).reduce((acm, cur) => acm || cur, false)) {             return rows;         }         const tmp: RowData[][] = [];         Object.entries(chips).forEach(([chip, enabled]) => {             if (enabled) {                 tmp.push(rows.filter((row) => row[chip]));             }         });         return tmp.flat();     },     sortHandler = (rows, sort) => {         sort.forEach(({             field,             sort,         }) => {             rows = rows.sort((a, b) => {                 if (sort === 'asc') {                     return compareFn(a[field], b[field]);                 } else if (sort === 'desc') {                     return compareFn(b[field], a[field]);                 }             });         });         return rows;     },     searchHandler = (rows, search) => {         if (rows.length > 0 &amp;&amp; search) {             return rows.filter((row) => {                 return String(row[\"title\"]).toLowerCase()                   .includes(search.toLowerCase());             });         } else {             return rows;         }     },     paginationHandler = (rows, {         limit,         offset,     }) => {         if (rows.length > limit) {             return rows.slice(offset, limit + offset);         } else {             return rows;         }     },     withPagination = true,     withFilters = true,     withChips = true,     withSort = true,     withTotal = true,     withSearch = true,     onError,     onLoadStart,     onLoadEnd, }: IArrayPaginatorParams&lt;FilterData, RowData> = {}) => {      const resolveRows = useMemo(() => async (         filterData: FilterData,         pagination: ListHandlerPagination,         sort: ListHandlerSortModel,         chips: ListHandlerChips,         search: string,     ) => {         if (typeof rowsHandler === 'function') {             return await rowsHandler(               filterData,               pagination,               sort,               chips,               search             );         } else {             return rowsHandler;         }     }, []);      const handler: Handler&lt;FilterData, RowData> = useMemo(() =>         async (filterData, pagination, sort, chips, search) => {           let isOk = true;           try {               onLoadStart &amp;&amp; onLoadStart();               const data = await resolveRows(                 filterData,                 pagination,                 sort,                 chips,                 search               );               let rows = Array.isArray(data) ? data : data.rows;               if (withFilters) {                   rows = filterHandler(rows.slice(0), filterData);               }               if (withChips) {                 rows = chipsHandler(rows.slice(0), chips);               }               if (withSort) {                   rows = sortHandler(rows.slice(0), sort);               }               if (withSearch) {                   rows = searchHandler(rows.slice(0), search);               }               if (withPagination) {                   rows = paginationHandler(rows.slice(0), pagination);               }               const total = Array.isArray(data)                 ? data.length                 : (data.total || null);               return {                   rows,                   total: withTotal ? total : null,               };           } catch (e) {               isOk = false;               if (onError) {                   onError(e as Error);                   return { ...EMPTY_RESPONSE };               } else {                   throw e;               }           } finally {               onLoadEnd &amp;&amp; onLoadEnd(isOk);           }     }, []);      return handler; };  export default useArrayPaginator;<\/code><\/pre>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0445\u0443\u043a <code>useArrayPaginator<\/code> \u0432 \u0441\u0432\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442 \u043a\u043e\u043b\u043b\u0431\u0435\u043a\u0438 <code>onLoadStart<\/code>, <code>onLoadEnd<\/code>, <code>onError<\/code> \u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438. \u041f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u043b\u0435\u0433\u043a\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <code>useApiPaginator<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0435\u0440\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a <a href=\"https:\/\/www.npmjs.com\/package\/nestjs-paginate\" rel=\"noopener noreferrer nofollow\">json:api<\/a><\/p>\n<h2>\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u043e\u043d\u043e\u043a<\/h2>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0438\u0436\u043a\u043e\u0432 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0441\/\u0431\u0435\u0437 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0441 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u044b\u043c \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043d\u0433\u043e\u043c \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439&#8230;<\/p>\n<pre><code class=\"typescript\">import { IColumn, List } from 'react-declatative';  const columns: IColumn&lt;IPerson>[] = [   {     type: ColumnType.Component,     headerName: 'Avatar',     width: () => 65,     phoneOrder: 1,     minHeight: 60,     element: ({ avatar }) => (       &lt;Box style={{ display: 'flex', alignItems: 'center' }}>         &lt;Avatar           src={avatar}           alt={avatar}         \/>       &lt;\/Box>     ),   },   {     type: ColumnType.Compute,     primary: true,     field: 'name',     headerName: 'Name',     width: (fullWidth) => Math.max(fullWidth * 0.1, 135),     compute: ({ firstName, lastName }) => `${firstName} ${lastName}`,     },   ...   {     type: ColumnType.Action,     headerName: 'Actions',     width: () => 50,   }, ];  ...  return (   &lt;List     handler={handler}     ...     columns={columns}   \/> ); <\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/15b\/091\/49d\/15b09149d8c23452ecacb44da9e3381b.png\" alt=\"\u0414\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430\" title=\"\u0414\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430\" width=\"1410\" height=\"483\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/15b\/091\/49d\/15b09149d8c23452ecacb44da9e3381b.png\"\/><figcaption>\u0414\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430<\/figcaption><\/figure>\n<p>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u0448\u0438\u0440\u0438\u043d\u0443 \u043a\u043e\u043b\u043e\u043d\u043a\u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043d\u043e\u0441 \u0442\u0435\u043a\u0441\u0442\u0430 \u043c\u0435\u043d\u044f\u043b \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u043b \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043d\u0433, \u043d\u043e \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043a\u0443 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7ac\/cff\/020\/7accff0200c757d5a73ab23c645aa78f.png\" alt=\"\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430\" title=\"\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430\" width=\"582\" height=\"449\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7ac\/cff\/020\/7accff0200c757d5a73ab23c645aa78f.png\"\/><figcaption>\u041c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0433\u0440\u0438\u0434\u0430<\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u0435\u043d\u044e \u0442\u0440\u0438 \u0442\u043e\u0447\u043a\u0438. \u0422\u0443\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u043b\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u043e\u0442\u0447\u0435\u0442\u0430 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430<\/p>\n<pre><code class=\"typescript\">import { IListRowAction, List } from 'react-declatative';  const rowActions: IListRowAction&lt;IPerson>[] = [   {     label: 'Export to excel',     action: 'excel-export',     isVisible: (person) => person.features.includes('excel-export'),   },   {     label: 'Remove draft',     action: 'remove-draft',     isDisabled: (person) => !person.features.includes('remove-draft'),     icon: Delete,   }, ];  return (   &lt;List     handler={handler}     columns={columns}     ...     rowActions={rowActions}   \/> );<\/code><\/pre>\n<p>\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0442\u0440\u0435\u0445 \u0442\u043e\u0447\u0435\u043a \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043b\u043b\u0431\u0435\u043a <code>isDisabled<\/code> \u0438 \u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043b\u043b\u0431\u0435\u043a <code>isVisible<\/code> . \u041e\u0431\u0430 \u043a\u043e\u043b\u043b\u0431\u0435\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 <code>boolean | Promise&lt;boolean><\/code>&#8230;<\/p>\n<h2>\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u0434 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438<\/h2>\n<p>\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0440\u0435\u0434\u043a\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0435\u043d\u044e &#171;\u0442\u0440\u0438 \u0442\u043e\u0447\u043a\u0438&#187; \u0432 <a href=\"https:\/\/mui.com\/material-ui\/api\/fab\" rel=\"noopener noreferrer nofollow\">FAB<\/a> \u0432 \u043f\u0440\u0430\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 \u0444\u043e\u0440\u043c\u044b. \u0422\u0443\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 Excel \u0434\u043b\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u043b\u0438 \u043a\u043d\u043e\u043f\u043a\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/650\/45e\/cde\/65045ecde8576f1dadbf54ff722d95c7.png\" width=\"263\" height=\"152\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/650\/45e\/cde\/65045ecde8576f1dadbf54ff722d95c7.png\"\/><figcaption><\/figcaption><\/figure>\n<pre><code class=\"typescript\">import { IListAction, List } from 'react-declarative';  const actions: IListAction&lt;IPerson>[] = [   {     type: ActionType.Add,     label: 'Create item'   },   {     type: ActionType.Fab,     label: 'Settings',   },   {     type: ActionType.Menu,     options: [       {         action: 'update-now',       },       {         action: 'resort-action',       },       {         action: 'excel-export',         label: 'Export to excel',         isDisabled: async (rows) => {           return rows.every(({ features }) =>             features.includes('excel-export')           );         },       },       {         action: 'disabled-action',         isDisabled: async (rows) => {           await sleep(5_000)           return true         },         label: 'Disabled',       },       {         action: 'hidden-action',         isVisible: (rows) => false,         label: 'Hidden',       },     ],   } ];  return (   &lt;List     handler={handler}     columns={columns}     rowActions={rowActions}     ...     actions={actions}   \/> );<\/code><\/pre>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0447\u0430\u0441\u0442\u043e, \u043b\u0443\u0447\u0448\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0430 \u0432\u0438\u0434\u0443 \u0434\u043b\u044f \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043b\u0438\u043a\u043e\u0432. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0444\u043b\u0430\u0436\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043a\u043e \u0432\u0441\u0435\u043c\u0443 \u0441\u043f\u0438\u0441\u043a\u0443, \u043d\u0435 \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u044f \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b backend id-\u0448\u043d\u0438\u043a\u0438<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b30\/e97\/be2\/b30e97be2268851c6c5f4e4af46d9667.png\" width=\"628\" height=\"275\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b30\/e97\/be2\/b30e97be2268851c6c5f4e4af46d9667.png\"\/><figcaption><\/figcaption><\/figure>\n<pre><code class=\"typescript\">import { IListOperation, List } from 'react-declarative';  const operations: IListOperation&lt;IPerson>[] = [   {     action: 'operation-one',     label: 'Operation one',   },   {     action: 'operation-two',     label: 'Operation two',     isAvailable: async (rows, isAll) => {       console.log({ rows, isAll })       return true;     }   },   {     action: 'operation-three',     label: 'Operation three',   }, ];  return (   &lt;List     handler={handler}     columns={columns}     rowActions={rowActions}     actions={actions}     ...     operations={operations}   \/> );<\/code><\/pre>\n<p>\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u0432 \u0442\u0440\u0435\u0445 \u0442\u043e\u0447\u043a\u0430\u0445 \u0442\u0430\u043a\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043a\u0440\u044b\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043b\u043b\u0431\u0435\u043a <code>isAvailable<\/code>. \u041e\u043d \u0442\u0430\u043a \u0436\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>boolean | Promise&lt;boolean><\/code>, \u043e\u0434\u043d\u0430\u043a\u043e, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430: \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0444\u043b\u0430\u0433 <code>isAll<\/code>. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441 backend \u043c\u0430\u0441\u0441\u0438\u0432 id-\u0448\u043d\u0438\u043a\u043e\u0432, \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u043e \u0432\u044b\u0448\u0435<\/p>\n<h2>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e \u0438\u043b\u0438 \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u043a\u043d\u043e\u043f\u043a\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043b\u043b\u0431\u0435\u043a\u0438<\/p>\n<pre><code class=\"typescript\">import { List } from 'react-declarative';  ...  const handleAction = (action: string, rows: IPerson) => {   if (action === 'excel-export') {     ...   } else if (...) {     ... };  const handleRowAction = (action: string, row: IPerson) => {   if (action === 'excel-export') {     ...   } else if (...) {     ... };  const handleOperation = (action: string, rows: IPerson, isAll: boolean) => {   if (action === 'operation-one') {     ...   } else if (...) {     ... };  return (   &lt;List     handler={handler}     columns={columns}     rowActions={rowActions}     actions={actions}     operations={operations}     ...     onAction={handleAction}     onRowAction={handleRowAction}     onOperation={handleOperation}   \/> );<\/code><\/pre>\n<h2>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e<\/h2>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 (\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043a\u0440\u044b\u0442\u044b\u0445 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0445) \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432. \u041c\u043e\u0436\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u043b\u0438\u0431\u043e \u043f\u043e JSON \u0448\u0430\u0431\u043b\u043e\u043d\u0443,<a href=\"https:\/\/v4.mui.com\/components\/data-grid\/components\/#overriding-components\" rel=\"noopener noreferrer nofollow\"> \u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u0441\u043b\u043e\u0442<\/a> &#8212; \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u043f\u0440\u043e\u043f\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8ea\/432\/1f7\/8ea4321f790ea6f5ee824faaa3bee11f.png\" alt=\"\" title=\"\" width=\"629\" height=\"348\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8ea\/432\/1f7\/8ea4321f790ea6f5ee824faaa3bee11f.png\"\/><figcaption><\/figcaption><\/figure>\n<pre><code class=\"typescript\">import { IField, List } from 'react-declarative';  const filters: IField[] = [   {     type: FieldType.Text,     name: 'firstName',     title: 'First name',   },   {     type: FieldType.Text,     name: 'lastName',     title: 'Last name',   } ];  return (   &lt;List     handler={handler}     columns={columns}     rowActions={rowActions}     actions={actions}     operations={operations}     ...     onAction={handleAction}     onRowAction={handleRowAction}     onOperation={handleOperation}     ...     filters={filters}   \/> );<\/code><\/pre>\n<h2>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0448\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u043d\u0435 \u0437\u043d\u0430\u0435\u0448\u044c \u0441 \u0447\u0435\u0433\u043e \u043d\u0430\u0447\u0430\u0442\u044c. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u0438 \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0430\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u044b)<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/677070\/\"> https:\/\/habr.com\/ru\/post\/677070\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\u00a0\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0437\u0430\u0434 \u043c\u043d\u0435 \u0434\u043e\u0432\u0435\u043b\u043e\u0441\u044c \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u043b\u044f \u0432\u0438\u0434\u0435\u043e\u0438\u0433\u0440\u044b \u0441 \u0443\u043a\u043b\u043e\u043d\u043e\u043c \u043d\u0430 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u044b\u0435 \u0441\u043e\u0440\u0435\u0432\u043d\u043e\u0432\u0430\u043d\u0438\u044f. \u0422\u0430\u043a \u043a\u0430\u043a \u0444\u0438\u043d\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u043b\u043e\u0441\u044c <a href=\"https:\/\/near.org\/grants\/\" rel=\"noopener noreferrer nofollow\">\u0437\u0430 \u0441\u0447\u0435\u0442 \u0433\u0440\u0430\u043d\u0442\u0430<\/a>, \u0431\u044b\u043b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0431\u044e\u0434\u0436\u0435\u0442<\/p>\n<p>\u0412\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044c \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e <strong>\u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0438<\/strong> \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u044b\u0445 \u0444\u043e\u0440\u043c \u0438 \u0444\u043e\u0440\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u0438\u0445 <strong>\u043c\u043e\u0433 \u043c\u0430\u0441\u0441\u043e\u0432\u043e \u043a\u043b\u0435\u043f\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0443\u0440\u043e\u0432\u043d\u044f Junior-<\/strong>. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0445\u043e\u0434\u0430 \u043d\u0430 \u0441\u0430\u043c\u043e\u043e\u043a\u0443\u043f\u0430\u0435\u043c\u043e\u0441\u0442\u044c, \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0435 \u0442\u0440\u0430\u0442\u044f \u0432\u0440\u0435\u043c\u044f \u0438 \u0434\u0435\u043d\u044c\u0433\u0438 \u043d\u0430 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433.<\/p>\n<p>\u0410\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u044c \u0432\u0430\u0436\u043d\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0441 \u0435\u0451 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a href=\"https:\/\/en.wikipedia.org\/wiki\/Know_your_customer\" rel=\"noopener noreferrer nofollow\">KYC<\/a> \u0438 \u0431\u0430\u043d \u0447\u0438\u0442\u0435\u0440\u043e\u0432. \u041e\u0434\u043d\u0430\u043a\u043e, \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u044d\u0442\u043e \u043d\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0434\u0435\u043d\u044c\u0433\u0438.<\/p>\n<h2>\u0410\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430<\/h2>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0440\u044b\u043d\u043a\u0435, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e<a href=\"https:\/\/devexpress.github.io\/devextreme-reactive\/react\/grid\/demos\/featured\/integrated-data-shaping\/\" rel=\"noopener noreferrer nofollow\"> DevExtreme React Grid<\/a>,  <a href=\"https:\/\/github.com\/bvaughn\/react-virtualized\/blob\/master\/docs\/Grid.md\" rel=\"noopener noreferrer nofollow\">ReactVirtualized Grid<\/a>, <a href=\"https:\/\/www.telerik.com\/kendo-react-ui\/components\/grid\/\" rel=\"noopener noreferrer nofollow\">KendoReact Data Grid<\/a>, <a href=\"https:\/\/mui.com\/x\/react-data-grid\/#commercial-version\" rel=\"noopener noreferrer nofollow\">MUI DataGridPro<\/a>. \u0412\u0441\u0435 \u043e\u043d\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0437\u0430 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0438\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">import * as React from 'react';  \/\/ import ...  const defaultTheme = createTheme(); const useStylesAntDesign = makeStyles(   (theme) => ({     \/\/ CSS-in-JS   }),   { defaultTheme }, );  const useStyles = makeStyles(   (theme) => ({     \/\/ CSS-in-JS   }),   { defaultTheme }, );  function SettingsPanel(props) {   const { onApply, type, size, theme } = props;   const [sizeState, setSize] = React.useState(size);   const [typeState, setType] = React.useState(type);   const [selectedPaginationValue, setSelectedPaginationValue] = React.useState(-1);   const [activeTheme, setActiveTheme] = React.useState(theme);    const handleSizeChange = React.useCallback((event) => {     setSize(Number(event.target.value));   }, []);    const handleDatasetChange = React.useCallback((event) => {     setType(event.target.value);   }, []);    const handlePaginationChange = React.useCallback((event) => {     setSelectedPaginationValue(event.target.value);   }, []);    const handleThemeChange = React.useCallback((event) => {     setActiveTheme(event.target.value);   }, []);    const handleApplyChanges = React.useCallback(() => {     onApply({       size: sizeState,       type: typeState,       pagesize: selectedPaginationValue,       theme: activeTheme,     });   }, [sizeState, typeState, selectedPaginationValue, activeTheme, onApply]);    return (     &lt;FormGroup className=\"MuiFormGroup-options\" row>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Dataset&lt;\/InputLabel>         &lt;Select value={typeState} onChange={handleDatasetChange}>           &lt;MenuItem value=\"Employee\">Employee&lt;\/MenuItem>           &lt;MenuItem value=\"Commodity\">Commodity&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Rows&lt;\/InputLabel>         &lt;Select value={sizeState} onChange={handleSizeChange}>           &lt;MenuItem value={100}>100&lt;\/MenuItem>           &lt;MenuItem value={1000}>{Number(1000).toLocaleString()}&lt;\/MenuItem>           &lt;MenuItem value={10000}>{Number(10000).toLocaleString()}&lt;\/MenuItem>           &lt;MenuItem value={100000}>{Number(100000).toLocaleString()}&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Page Size&lt;\/InputLabel>         &lt;Select value={selectedPaginationValue} onChange={handlePaginationChange}>           &lt;MenuItem value={-1}>off&lt;\/MenuItem>           &lt;MenuItem value={0}>auto&lt;\/MenuItem>           &lt;MenuItem value={25}>25&lt;\/MenuItem>           &lt;MenuItem value={100}>100&lt;\/MenuItem>           &lt;MenuItem value={1000}>{Number(1000).toLocaleString()}&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;FormControl variant=\"standard\">         &lt;InputLabel>Theme&lt;\/InputLabel>         &lt;Select value={activeTheme} onChange={handleThemeChange}>           &lt;MenuItem value=\"default\">Default Theme&lt;\/MenuItem>           &lt;MenuItem value=\"ant\">Ant Design&lt;\/MenuItem>         &lt;\/Select>       &lt;\/FormControl>       &lt;Button         size=\"small\"         variant=\"outlined\"         color=\"primary\"         onClick={handleApplyChanges}       >         &lt;KeyboardArrowRightIcon fontSize=\"small\" \/> Apply       &lt;\/Button>     &lt;\/FormGroup>   ); }  SettingsPanel.propTypes = {   onApply: PropTypes.func.isRequired,   size: PropTypes.number.isRequired,   theme: PropTypes.oneOf(['ant', 'default']).isRequired,   type: PropTypes.oneOf(['Commodity', 'Employee']).isRequired, };  export default function FullFeaturedDemo() {   const classes = useStyles();   const antDesignClasses = useStylesAntDesign();   const [isAntDesign, setIsAntDesign] = React.useState(false);   const [type, setType] = React.useState('Commodity');   const [size, setSize] = React.useState(100);   const { loading, data, setRowLength, loadNewData } = useDemoData({     dataSet: type,     rowLength: size,     maxColumns: 40,     editable: true,   });    const [pagination, setPagination] = React.useState({     pagination: false,     autoPageSize: false,     pageSize: undefined,   });    const getActiveTheme = () => {     return isAntDesign ? 'ant' : 'default';   };    const handleApplyClick = (settings) => {     if (size !== settings.size) {       setSize(settings.size);     }      if (type !== settings.type) {       setType(settings.type);     }      if (getActiveTheme() !== settings.theme) {       setIsAntDesign(!isAntDesign);     }      if (size !== settings.size || type !== settings.type) {       setRowLength(settings.size);       loadNewData();     }      const newPaginationSettings = {       pagination: settings.pagesize !== -1,       autoPageSize: settings.pagesize === 0,       pageSize: settings.pagesize > 0 ? settings.pagesize : undefined,     };      setPagination((currentPaginationSettings) => {       if (         currentPaginationSettings.pagination === newPaginationSettings.pagination &amp;&amp;         currentPaginationSettings.autoPageSize ===           newPaginationSettings.autoPageSize &amp;&amp;         currentPaginationSettings.pageSize === newPaginationSettings.pageSize       ) {         return currentPaginationSettings;       }       return newPaginationSettings;     });   };    return (     &lt;div className={classes.root}>       &lt;SettingsPanel         onApply={handleApplyClick}         size={size}         type={type}         theme={getActiveTheme()}       \/>       &lt;DataGridPro         className={isAntDesign ? antDesignClasses.root : undefined}         {...data}         components={{           Toolbar: GridToolbar,         }}         loading={loading}         checkboxSelection         disableSelectionOnClick         {...pagination}       \/>     &lt;\/div>   ); } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 DataGridPro <a href=\"https:\/\/codesandbox.io\/s\/nasty-mui-datagridpro-sample-uchw3m\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0436\u043d\u043e \u0442\u0443\u0442<\/a>. \u041f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e \u0432\u0435\u0434\u0435\u0442 \u043a \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u0430\u0434\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0430 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043e\u043a, \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438 \u043b\u044f\u0436\u0435\u0442 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u0435\u0440\u0442\u0432\u044b\u043c \u0433\u0440\u0443\u0437\u043e\u043c legacy<\/p>\n<h2>\u0422\u0435\u0437\u0438\u0441\u044b \u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0445 \u043a\u043e\u0434\u0430 \u0432\u044b\u0448\u0435<\/h2>\n<ol>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 <code>useState<\/code>, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 <code>type<\/code>, <code>size<\/code> \u0438  <code>pagination<\/code> \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433, \u043a\u043e\u0433\u0434\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c, \u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e  \u043d\u0435 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b. \u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0435\u0434\u0438\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e (\u0441\u043c \u043a\u043d\u043e\u043f\u043a\u0443 <em>Apply<\/em>)?<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>SettingsPanel <\/code>\u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u0421\u043f\u043e\u0440\u043d\u043e, \u043d\u043e \u043f\u043e \u043c\u043e\u0435\u043c\u0443, \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u0435\u0440\u043d\u0435\u0442 <code>JSX.Element<\/code>, \u0430 \u043d\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/p>\n<\/li>\n<li>\n<p>\u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438 \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 backend? \u041a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 status-500, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443?<\/p>\n<\/li>\n<\/ol>\n<h2>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/h2>\n<ol>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0447\u0438\u0441\u0442\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 <code>filterData<\/code>, <code>limit<\/code>, <code>offset<\/code> \u0438 \u0442.\u0434., \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043b\u0438\u0431\u043e \u043c\u0430\u0441\u0441\u0438\u0432, \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u043c\u0438\u0441 \u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0444\u0438\u0440\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 <code>SettingsPanel<\/code>. \u0418\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u043f\u0441\u044b, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 (<em>\u043f\u0443\u043d\u043a\u0442 1<\/em>) \u0432\u043a\u043b\u044e\u0447\u0438\u0442 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442 \u0435\u0433\u043e \u0432 \u0431\u043b\u043e\u043a\u0435 <code>finally<\/code> \u0438, \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u043e\u043f\u043e\u0432\u0435\u0441\u0442\u0438\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e status-500<\/p>\n<\/li>\n<\/ol>\n<h2>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e<\/h2>\n<p>\u041d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u043a\u043d\u043e\u043f\u043e\u043a \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u0438\u0433\u043b\u0430\u0441\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u043e\u0432 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e? \u041d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043b\u043e\u043d\u043a\u0443 &#171;\u0421\u0442\u0430\u0442\u0443\u0441 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f&#187; \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 &#171;\u041f\u0440\u0438\u0433\u043b\u0430\u0441\u0438\u0442\u044c&#187;. \u041e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0434\u043b\u044f \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c. <\/p>\n<figure class=\"full-width\"><figcaption>MUI DataGridPro<\/figcaption><\/figure>\n<p>\u0410 \u0435\u0449\u0451, \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u0442\u0440\u0435\u0439\u0434\u0435\u0440\u0430\u043c \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0432 \u0441\u043f\u0438\u0441\u043a\u0435. <\/p>\n<h3>\u0427\u0438\u0441\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430 \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0433\u0440\u0438\u0434\u0430, \u044f \u0431\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u043f\u0441\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043e\u0447\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u0447\u0438\u0441\u0442\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u043c<\/p>\n<pre><code class=\"typescript\">import { List } from 'react-declarative';  type RowId = string | number;  interface IRowData {   id: RowId; }  type HandlerPagination = {   limit: number;   offset: number; };  type HandlerSortModel&lt;RowData extends IRowData = any> = {   field: keyof RowData;   sort: 'asc' | 'desc'; }[];  type HandlerChips&lt;RowData extends IRowData = any> =    Record&lt;keyof RowData, boolean>;  type HandlerResult&lt;RowData extends IRowData = IAnything> = {   rows: RowData[];   total: number | null; };  type Handler&lt;FilterData = any, RowData extends IRowData = any> = (   filterData: FilterData,   pagination: ListHandlerPagination,   sort: ListHandlerSortModel&lt;RowData>,   chips: ListHandlerChips&lt;RowData>,   search: string, ) => Promise&lt;HandlerResult&lt;RowData>> | HandlerResult&lt;RowData>;  const handler: Handler = (filterData, pagination, sort, chips, search) => { ... };  ...  &lt;List   handler={handler}   ... \/><\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>handler<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u044f\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432<\/p>\n<ol>\n<li>\n<p><strong>filterData<\/strong> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 SettingsPanel, \u0443\u0441\u043b\u043e\u0432\u043d\u043e. \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 ComboBox, \u0441\u043b\u0430\u0439\u0434\u0435\u0440\u0430\u043c\u0438 \u0438 \u0442.\u0434.<\/p>\n<\/li>\n<li>\n<p><strong>pagination<\/strong> &#8212; \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u0434\u0432\u0443\u043c\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: <code>limit<\/code> \u0438 <code>offset<\/code>\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-335751","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/335751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=335751"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/335751\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=335751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=335751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=335751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}