我有一个名为filterContactsByValue
的函数。它是curry并接收值和联系人列表,然后根据值过滤列表并返回(新)过滤列表。
由于列表通常很大(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
);
根据https://github.com/xnimorz/use-debounce你已经有useDebouncedCallback
钩。
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>
);
}
简短回答:使用useMemo
而不是useCallback
,如下所示:
const filteredContacts = useMemo(() => filterContacts(contacts), [
value
]);
...
<ContactList contacts={filteredContacts} />
为什么? useCallback
记住了函数的创建。意思是,如果diffing参数相同,函数的引用将是相同的。它每次都会被调用,在你的情况下,不会阻止任何计算。
如果value
发生变化,你想要的只是过滤你的联系人。 useMemo
会记住函数的最后一个返回值,并且只会在diffing参数更改时重新运行。并且它们每800毫秒不会改变超过一次,因为你很好地去除了它。
PS:您可以使用useCallback
来防止filterContacts
无缘无故重新计算:
const filterContacts = useCallback(() => filterContactsByValue(value.toLowerCase(), [value]);
即便如此,性能提升也很小。