REACT:如果USECALLBACK返回值,或者这是一个不好的模式,可以吗?



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>
    );
}

最新更新