add a debounce hook
This commit is contained in:
parent
8f515701fa
commit
e4c440e211
31
platform/viewer/src/hooks/useDebounce.js
Normal file
31
platform/viewer/src/hooks/useDebounce.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* See: https://usehooks.com/useDebounce/
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {number} delay - delat in ms
|
||||
*/
|
||||
export default function useDebounce(value, delay) {
|
||||
// State and setters for debounced value
|
||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
// Update debounced value after delay
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value);
|
||||
}, delay);
|
||||
|
||||
// Cancel the timeout if value changes (also on delay change or unmount)
|
||||
// This is how we prevent debounced value from updating if value is changed ...
|
||||
// .. within the delay period. Timeout gets cleared and restarted.
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
},
|
||||
[value, delay] // Only re-call effect if value or delay changes
|
||||
);
|
||||
|
||||
return debouncedValue;
|
||||
}
|
||||
@ -1,10 +1,13 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import propTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
import qs from 'query-string';
|
||||
//
|
||||
import { useDebounce, useQuery } from './../../hooks';
|
||||
|
||||
import {
|
||||
utils,
|
||||
Icon,
|
||||
StudyListExpandedRow,
|
||||
Button,
|
||||
@ -17,31 +20,50 @@ import {
|
||||
StudyListFilter,
|
||||
} from '@ohif/ui';
|
||||
|
||||
// URL Query Hook
|
||||
import { useQuery } from '../../hooks';
|
||||
|
||||
function StudyListContainer() {
|
||||
/**
|
||||
* TODO:
|
||||
* - debounce `setFilterValues` (150ms?)
|
||||
*/
|
||||
function StudyListContainer({ history, studies }) {
|
||||
// ~ Filters
|
||||
const query = useQuery();
|
||||
|
||||
const defaultFilterValues = {
|
||||
patientName: '',
|
||||
mrn: '',
|
||||
studyDate: {
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
},
|
||||
description: '',
|
||||
modality: undefined,
|
||||
accession: '',
|
||||
sortBy: '',
|
||||
sortDirection: 'none',
|
||||
page: 0,
|
||||
resultsPerPage: 25,
|
||||
};
|
||||
const [filterValues, setFilterValues] = useState(defaultFilterValues);
|
||||
const studies = utils.getMockedStudies(100);
|
||||
const numOfStudies = studies.length;
|
||||
const queryFilterValues = _getQueryFilterValues(query);
|
||||
const [filterValues, setFilterValues] = useState(
|
||||
Object.assign({}, defaultFilterValues, queryFilterValues)
|
||||
);
|
||||
const debouncedFilterValues = useDebounce(filterValues, 500);
|
||||
// ~ Rows & Studies
|
||||
const [expandedRows, setExpandedRows] = useState([]);
|
||||
const numOfStudies = studies.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (!debouncedFilterValues) {
|
||||
return;
|
||||
}
|
||||
const queryString = {};
|
||||
Object.keys(defaultFilterValues).forEach(key => {
|
||||
const defaultValue = defaultFilterValues[key];
|
||||
const currValue = debouncedFilterValues[key];
|
||||
|
||||
if (
|
||||
typeof currValue === 'object' &&
|
||||
currValue !== null &&
|
||||
JSON.stringify(currValue) !== JSON.stringify(defaultValue)
|
||||
) {
|
||||
queryString[key] = JSON.stringify(currValue);
|
||||
} else if (currValue !== defaultValue) {
|
||||
queryString[key] = currValue;
|
||||
}
|
||||
});
|
||||
history.push({
|
||||
pathname: '/',
|
||||
search: `?${qs.stringify(queryString, {
|
||||
skipNull: true,
|
||||
skipEmptyString: true,
|
||||
})}`,
|
||||
});
|
||||
}, [debouncedFilterValues, history]);
|
||||
|
||||
const filtersMeta = [
|
||||
{
|
||||
name: 'patientName',
|
||||
@ -259,10 +281,6 @@ function StudyListContainer() {
|
||||
|
||||
const hasStudies = numOfStudies > 0;
|
||||
|
||||
useEffect(() => {
|
||||
query.setQueryString(filterValues);
|
||||
}, [filterValues, query]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames('bg-black h-full', {
|
||||
@ -296,7 +314,7 @@ function StudyListContainer() {
|
||||
numOfStudies={numOfStudies}
|
||||
filtersMeta={filtersMeta}
|
||||
filterValues={filterValues}
|
||||
setFilterValues={setFilterValues}
|
||||
onChange={setFilterValues}
|
||||
clearFilters={() => setFilterValues(defaultFilterValues)}
|
||||
isFiltering={isFiltering(filterValues, defaultFilterValues)}
|
||||
/>
|
||||
@ -326,4 +344,85 @@ function StudyListContainer() {
|
||||
);
|
||||
}
|
||||
|
||||
StudyListContainer.propTypes = {
|
||||
history: propTypes.shape({
|
||||
push: propTypes.func,
|
||||
}),
|
||||
studies: propTypes.array,
|
||||
};
|
||||
|
||||
StudyListContainer.defaultProps = {
|
||||
studies: [],
|
||||
};
|
||||
|
||||
const defaultFilterValues = {
|
||||
patientName: '',
|
||||
mrn: '',
|
||||
studyDate: {
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
},
|
||||
description: '',
|
||||
modality: [],
|
||||
accession: '',
|
||||
sortBy: '',
|
||||
sortDirection: 'none',
|
||||
page: 0,
|
||||
resultsPerPage: 25,
|
||||
};
|
||||
|
||||
function _getQueryFilterValues(query) {
|
||||
const queryFilterValues = {
|
||||
patientName: query.get('patientName'),
|
||||
mrn: query.get('mrn'),
|
||||
studyDate: _tryParseDates(query.get('studyDate'), undefined),
|
||||
description: query.get('description'),
|
||||
modality: _tryParseJson(query.get('modality'), undefined),
|
||||
accession: query.get('accession'),
|
||||
sortBy: query.get('soryBy'),
|
||||
sortDirection: query.get('sortDirection'),
|
||||
page: _tryParseInt(query.get('page'), undefined),
|
||||
resultsPerPage: _tryParseInt(query.get('resultsPerPage'), undefined),
|
||||
};
|
||||
|
||||
// Delete null/undefined keys
|
||||
Object.keys(queryFilterValues).forEach(
|
||||
key => queryFilterValues[key] == null && delete queryFilterValues[key]
|
||||
);
|
||||
|
||||
return queryFilterValues;
|
||||
|
||||
function _tryParseInt(str, defaultValue) {
|
||||
var retValue = defaultValue;
|
||||
if (str !== null) {
|
||||
if (str.length > 0) {
|
||||
if (!isNaN(str)) {
|
||||
retValue = parseInt(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
function _tryParseJson(str, defaultValue) {
|
||||
return str ? JSON.parse(str) : defaultValue;
|
||||
}
|
||||
|
||||
function _tryParseDates(str, defaultValue) {
|
||||
const studyDateObject = _tryParseJson(str, defaultValue);
|
||||
|
||||
if (studyDateObject) {
|
||||
studyDateObject.startDate = studyDateObject.startDate
|
||||
? moment(new Date(studyDateObject.startDate))
|
||||
: undefined;
|
||||
|
||||
studyDateObject.endDate = studyDateObject.endDate
|
||||
? moment(new Date(studyDateObject.endDate))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
return studyDateObject;
|
||||
}
|
||||
}
|
||||
|
||||
export default StudyListContainer;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user