浏览代码

Add filter and sort functionality

paging-sorting-filtering
mladen.dubovac 4 年前
父节点
当前提交
6bc926e947

+ 80
- 14
src/components/MUI/Examples/PagingSortingFilteringExample.js 查看文件

Typography, Typography,
Divider, Divider,
TablePagination, TablePagination,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
} from '@mui/material'; } from '@mui/material';
// import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector, batch } from 'react-redux'; import { useDispatch, useSelector, batch } from 'react-redux';
pageSelector, pageSelector,
itemsPerPageSelector, itemsPerPageSelector,
countSelector, countSelector,
filterSelector,
sortSelector,
} from '../../../store/selectors/randomDataSelectors'; } from '../../../store/selectors/randomDataSelectors';
import { import {
loadData, loadData,
updatePage, updatePage,
updateItemsPerPage, updateItemsPerPage,
updateFilter,
updateSort,
} from '../../../store/actions/randomData/randomDataActions'; } from '../../../store/actions/randomData/randomDataActions';


const PagingSortingFilteringExample = () => { const PagingSortingFilteringExample = () => {
const currentPage = useSelector(pageSelector); const currentPage = useSelector(pageSelector);
const itemsPerPage = useSelector(itemsPerPageSelector); const itemsPerPage = useSelector(itemsPerPageSelector);
const totalCount = useSelector(countSelector); const totalCount = useSelector(countSelector);
const filter = useSelector(filterSelector);
const sort = useSelector(sortSelector) || 'name-asc';


useEffect(() => { useEffect(() => {
dispatch(loadData(30)); dispatch(loadData(30));
dispatch(updateSort(sort));
}, []); }, []);


const handlePageChange = (event, newPage) => { const handlePageChange = (event, newPage) => {
}); });
}; };


const handleFilterChange = (event) => {
const filter = event.target.value;
batch(() => {
dispatch(updateFilter(filter));
currentPage > 0 && dispatch(updatePage(0));
});
};

const handleSortChange = (event) => {
const sort = event.target.value;
dispatch(updateSort(sort));
};

return ( return (
<Paper <Paper
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
justifyContent: 'center',
justifyContent: 'start',
py: 2,
minHeight: 500,
}} }}
elevation={5} elevation={5}
> >
<Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center"> <Typography sx={{ my: 4 }} variant="h4" gutterBottom align="center">
Pagination, Filtering and Sorting Example Pagination, Filtering and Sorting Example
</Typography> </Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Box>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
mx: 2,
}}
>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
width: '100%',
}}
>
{/* TODO Separate into SelectComponent */}
<FormControl sx={{ flexGrow: 1 }}>
<InputLabel id="sort-label">Sort</InputLabel>
<Select
label="Sort"
labelId="sort-label"
id="sort-select-helper"
value={sort}
onChange={handleSortChange}
>
<MenuItem value="name-asc">Name - A-Z</MenuItem>
<MenuItem value="name-desc">Name - Z-A</MenuItem>
<MenuItem value="price-asc">Price - Lowest to Highest</MenuItem>
<MenuItem value="price-desc">Price - Highest to Lowest</MenuItem>
</Select>
</FormControl>
<TextField
sx={{ flexGrow: 1 }}
variant="outlined"
label="Filter"
placeholder="Filter"
value={filter}
onChange={handleFilterChange}
/> />
</Box> </Box>
</Box> </Box>
</Grid> </Grid>
))} ))}
</Grid> </Grid>
<Box sx={{ width: '100%' }}>
<TablePagination
component="div"
count={totalCount}
page={currentPage}
onPageChange={handlePageChange}
rowsPerPage={itemsPerPage}
onRowsPerPageChange={handleItemsPerPageChange}
rowsPerPageOptions={[12, 24, 48, 96]}
labelRowsPerPage="Items per page"
showFirstButton
showLastButton
/>
</Box>
</Paper> </Paper>
); );
}; };

+ 2
- 0
src/store/actions/randomData/randomDataActionConstants.js 查看文件

export const LOAD_DATA = 'LOAD_DATA'; export const LOAD_DATA = 'LOAD_DATA';
export const UPDATE_PAGE = 'UPDATE_PAGE'; export const UPDATE_PAGE = 'UPDATE_PAGE';
export const UPDATE_ITEMS_PER_PAGE = 'UPDATE_ITEMS_PER_PAGE'; export const UPDATE_ITEMS_PER_PAGE = 'UPDATE_ITEMS_PER_PAGE';
export const UPDATE_FILTER = 'UPDATE_FILTER';
export const UPDATE_SORT = 'UPDATE_SORT';

+ 12
- 0
src/store/actions/randomData/randomDataActions.js 查看文件

LOAD_DATA, LOAD_DATA,
UPDATE_PAGE, UPDATE_PAGE,
UPDATE_ITEMS_PER_PAGE, UPDATE_ITEMS_PER_PAGE,
UPDATE_FILTER,
UPDATE_SORT
} from './randomDataActionConstants'; } from './randomDataActionConstants';


export const loadData = (payload) => ({ export const loadData = (payload) => ({
type: UPDATE_ITEMS_PER_PAGE, type: UPDATE_ITEMS_PER_PAGE,
payload, payload,
}); });

export const updateFilter = (payload) => ({
type: UPDATE_FILTER,
payload,
})

export const updateSort = (payload) => ({
type: UPDATE_SORT,
payload,
})

+ 52
- 0
src/store/reducers/randomData/randomDataReducer.js 查看文件

LOAD_DATA, LOAD_DATA,
UPDATE_PAGE, UPDATE_PAGE,
UPDATE_ITEMS_PER_PAGE, UPDATE_ITEMS_PER_PAGE,
UPDATE_FILTER,
UPDATE_SORT,
} from '../../actions/randomData/randomDataActionConstants.js'; } from '../../actions/randomData/randomDataActionConstants.js';
import generate from '../../../util/helpers/randomData'; import generate from '../../../util/helpers/randomData';


const initialState = { const initialState = {
items: [], items: [],
filteredItems: [],
count: 0, count: 0,
page: 0, page: 0,
itemsPerPage: 12, itemsPerPage: 12,
filter: '',
sort: '',
}; };


export default createReducer( export default createReducer(
[LOAD_DATA]: loadRandomData, [LOAD_DATA]: loadRandomData,
[UPDATE_PAGE]: updatePage, [UPDATE_PAGE]: updatePage,
[UPDATE_ITEMS_PER_PAGE]: updateItemsPerPage, [UPDATE_ITEMS_PER_PAGE]: updateItemsPerPage,
[UPDATE_FILTER]: updateFilter,
[UPDATE_SORT]: updateSort,
}, },
initialState initialState
); );
return { return {
...state, ...state,
items, items,
filteredItems: items,
count: items.length, count: items.length,
}; };
} }
itemsPerPage, itemsPerPage,
}; };
} }

function updateFilter(state, action) {
const filter = action.payload;
const filteredItems = filter
? state.items.filter((item) => item.name.toLowerCase().includes(filter.toLowerCase())) : state.items;

return {
...state,
filter,
filteredItems,
count: filteredItems.length,
};
}

function updateSort(state, action) {
const sort = action.payload;
const [field, direction] = sort.split('-');

const sortDirection = direction === 'asc' ? 1 : -1;
const dataItems = state.filteredItems.length
? state.filteredItems
: state.items;

const sorted = dataItems.sort((a, b) => {
if (a[field] > b[field]) {
return sortDirection;
}
if (b[field] > a[field]) {
return sortDirection * -1;
}
});

const items = state.items.length ? sorted : state.items;
const filteredItems = state.filteredItems.length
? sorted
: state.filteredItems;

return {
...state,
sort,
items,
filteredItems,
};
}

+ 12
- 3
src/store/selectors/randomDataSelectors.js 查看文件



const randomDataSelector = (state) => state.randomData; const randomDataSelector = (state) => state.randomData;


export const itemsSelector = createSelector(
randomDataSelector,
(state) => state.items
export const itemsSelector = createSelector(randomDataSelector, (state) =>
(state.filter) ? state.filteredItems : state.items
); );


export const pageSelector = createSelector( export const pageSelector = createSelector(
randomDataSelector, randomDataSelector,
(state) => state.count (state) => state.count
); );

export const filterSelector = createSelector(
randomDataSelector,
(state) => state.filter
);

export const sortSelector = createSelector(
randomDataSelector,
(state) => state.sort
);

正在加载...
取消
保存