Factor out input to isolate component updates
This commit is contained in:
parent
5048c460f1
commit
652d98f6c6
2 changed files with 39 additions and 14 deletions
36
ui/component/common/debounced-input.jsx
Normal file
36
ui/component/common/debounced-input.jsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Icon from 'component/common/icon';
|
||||
import useDebounce from 'effects/use-debounce';
|
||||
|
||||
const FILTER_DEBOUNCE_MS = 300;
|
||||
|
||||
interface Props {
|
||||
icon?: string;
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
onChange: (newValue: string) => any;
|
||||
}
|
||||
|
||||
export default function DebouncedInput(props: Props) {
|
||||
const { icon, value = '', placeholder = '', onChange } = props;
|
||||
const [rawValue, setRawValue] = useState(value);
|
||||
const debouncedValue: string = useDebounce(rawValue, FILTER_DEBOUNCE_MS);
|
||||
|
||||
useEffect(() => {
|
||||
onChange(debouncedValue);
|
||||
}, [onChange, debouncedValue]);
|
||||
|
||||
return (
|
||||
<div className="wunderbar">
|
||||
{icon && <Icon icon={icon} />}
|
||||
<input
|
||||
className="wunderbar__input"
|
||||
spellCheck={false}
|
||||
placeholder={placeholder}
|
||||
value={rawValue}
|
||||
onChange={(e) => setRawValue(e.target.value.trim())}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -8,15 +8,14 @@ import Button from 'component/button';
|
|||
import classnames from 'classnames';
|
||||
import Icon from 'component/common/icon';
|
||||
import NotificationBubble from 'component/notificationBubble';
|
||||
import DebouncedInput from 'component/common/debounced-input';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import ChannelThumbnail from 'component/channelThumbnail';
|
||||
import useDebounce from 'effects/use-debounce';
|
||||
import { useIsMobile, useIsLargeScreen } from 'effects/use-screensize';
|
||||
import { GetLinksData } from 'util/buildHomepage';
|
||||
import { DOMAIN, ENABLE_UI_NOTIFICATIONS, ENABLE_NO_SOURCE_CLAIMS, CHANNEL_STAKED_LEVEL_LIVESTREAM } from 'config';
|
||||
|
||||
const FOLLOWED_ITEM_INITIAL_LIMIT = 10;
|
||||
const FILTER_DEBOUNCE_MS = 300;
|
||||
|
||||
type SideNavLink = {
|
||||
title: string,
|
||||
|
@ -252,8 +251,7 @@ function SideNavigation(props: Props) {
|
|||
const showSubscriptionSection = shouldRenderLargeMenu && isPersonalized && subscriptions && subscriptions.length > 0;
|
||||
const showTagSection = sidebarOpen && isPersonalized && followedTags && followedTags.length;
|
||||
|
||||
const [rawSubscriptionFilter, setRawSubscriptionFilter] = React.useState('');
|
||||
const subscriptionFilter: string = useDebounce(rawSubscriptionFilter, FILTER_DEBOUNCE_MS);
|
||||
const [subscriptionFilter, setSubscriptionFilter] = React.useState('');
|
||||
|
||||
const filteredSubscriptions = subscriptions.filter(
|
||||
(sub) => !subscriptionFilter || sub.channelName.toLowerCase().includes(subscriptionFilter)
|
||||
|
@ -307,16 +305,7 @@ function SideNavigation(props: Props) {
|
|||
<>
|
||||
<ul className="navigation__secondary navigation-links">
|
||||
<li className="navigation-item">
|
||||
<div className="wunderbar">
|
||||
<Icon icon={ICONS.SEARCH} />
|
||||
<input
|
||||
className="wunderbar__input"
|
||||
spellCheck={false}
|
||||
placeholder={__('Filter')}
|
||||
value={rawSubscriptionFilter}
|
||||
onChange={(e) => setRawSubscriptionFilter(e.target.value.trim())}
|
||||
/>
|
||||
</div>
|
||||
<DebouncedInput icon={ICONS.SEARCH} placeholder={__('Filter')} onChange={setSubscriptionFilter} />
|
||||
</li>
|
||||
{displayedSubscriptions.map((subscription) => (
|
||||
<SubscriptionListItem key={subscription.uri} subscription={subscription} />
|
||||
|
|
Loading…
Reference in a new issue