i具有称为 filterContactsByValue
的函数。它是咖喱的,并占用一个值和联系人列表,然后根据值过滤列表,并返回(新的)过滤列表。
由于列表通常很大(10.000多个条目),因此Web应用程序应在智能手机上运行,并且过滤器考虑了许多值,我想优化计算资源。因此,我使用useDebounce
不必要计算。
我还使用了这样的useCallback
来记忆filteredContacts
的计算:
function FilteredContacts({contacts}) {
const [filterParam, setFilterParam] = useState('');
const [value] = useDebounce(filterParam, 800);
const filterContacts = filterContactsByValue(value.toLowerCase());
// Is this okay? 🤔 ...
const getFilteredContacts = useCallback(() => filterContacts(contacts), [
value
]);
return (
<div className="main">
<SearchBar
value={filterParam}
onChangeText={setFilterParam}
/>
// ... and then this? 🧐
<ContactList contacts={getFilteredContacts()} />
</div>
);
}
我想知道这是否还可以,或者像这样返回的价值观是不好的做法。如果不好,为什么以及如何改进它?
编辑:filterContactsByValue
功能:
import { any, filter, includes, map, pick, pipe, toLower, values } from 'ramda';
import { stringFields } from './config/constants';
const contactIncludesValue = value =>
pipe(
pick(stringFields),
map(toLower),
values,
any(includes(value))
);
const filterContactsByValue = pipe(
contactIncludesValue,
filter
);
简短答案:使用useMemo
代替useCallback
,例如:
const filteredContacts = useMemo(() => filterContacts(contacts), [
value
]);
...
<ContactList contacts={filteredContacts} />
为什么?useCallback
记住函数的创建。含义,如果扩散参数相同,则函数的引用将相同。不过,它仍然每次都会被调用,在您的情况下,它不会阻止任何计算。
您想要的是仅在value
更改时过滤您的联系人。useMemo
记住您功能的最后一个返回值,并且只有在扩散参数更改时才会重新运行。而且它们不会每800毫秒更改一次,因为您会很好地审核它。
ps:您可以使用useCallback
防止filterContacts
无缘无故地重新计算:
const filterContacts = useCallback(() => filterContactsByValue(value.toLowerCase()), [value]);
即使在您的情况下,性能也很小。
根据https://github.com/xnimorz/use-debounce,您已经有useDebouncedCallback
Hook。
const getFilteredContacts = useDebouncedCallback(
() => filterContactsByValue(value.toLowerCase()),
800,
[value]
);
您也可以使用lodash的访问或油门(当您的项目中有lodash时),但是正如@skyboyer所提到的那样,您可以在适当的延迟后以过时的回调版本结尾。
export {debounce} from 'lodash';
const getFilteredContacts = useCallback(
debounce(() => filterContactsByValue(value.toLowerCase()), 1000),
[value]
);
但是useMemo
将是更好的选择,因为您不希望在渲染方法中执行函数
const FilteredContacts = ({contacts}) => {
const [filterParam, setFilterParam] = useState('');
const [value] = useDebounce(filterParam, 800);
const contactsFilter = useMemo(
() => filterContactsByValue(value.toLowerCase()),
[value]
);
const filteredContacts = useMemo(
() => contactsFilter(contacts),
[value, contacts]
);
return (
<div className="main">
<SearchBar
value={filterParam}
onChangeText={setFilterParam}
/>
<ContactList contacts={filteredContacts} />
</div>
);
}