Skip to content

Instantly share code, notes, and snippets.

@cephalization
Created March 30, 2022 22:36
Show Gist options
  • Select an option

  • Save cephalization/ffbf0e353dd77ad02c176163105afb52 to your computer and use it in GitHub Desktop.

Select an option

Save cephalization/ffbf0e353dd77ad02c176163105afb52 to your computer and use it in GitHub Desktop.
Incorrect useTransition usage
import React, { useCallback, useEffect, useState, useTransition } from 'react';
import { useAppDispatch, useAppSelector } from '~/hooks';
import { libraryActions } from '~/store/slices/library/library';
import { librarySelectors } from '~/store/slices/library/selectors';
// Search input
// Dispatches redux thunk when text input changes
export function TrackSearch() {
const dispatch = useAppDispatch();
const libraryFilter = useAppSelector(librarySelectors.selectLibraryFilter);
const [localFilter, setLocalFilter] = useState(libraryFilter);
const [_, startTransition] = useTransition()
// synchronize local input state with redux when redux changes outside of this component
useEffect(() => {
if (localFilter !== libraryFilter) {
setLocalFilter(libraryFilter);
}
}, [libraryFilter]);
// set the local input state onchange
const onChange = useCallback(
(e) => {
const value = e.target.value;
setLocalFilter(value);
},
[setLocalFilter],
);
// dispatch the local input state to a redux thunk that will fetch search results
// NOTE: this does not work the way that I immediately thought it would
// transitions help with react state updates, not external state updates
// this process cannot be interrupted by react
startTransition(() => {
dispatch(libraryActions.setLibraryFilter({ localFilter }));
})
return (
<div>
<form action="#" method="GET">
<input
name="search_field"
placeholder="Search your library"
type="search"
value={localFilter}
onChange={onChange}
/>
</form>
</div>
);
}
import { SearchIcon } from '@heroicons/react/outline';
import debounce from 'lodash.debounce';
import React, { useCallback, useEffect, useState } from 'react';
import { useAppDispatch, useAppSelector } from '~/hooks';
import { libraryActions } from '~/store/slices/library/library';
import { librarySelectors } from '~/store/slices/library/selectors';
export function TrackSearch() {
const dispatch = useAppDispatch();
const libraryFilter = useAppSelector(librarySelectors.selectLibraryFilter);
const [localFilter, setLocalFilter] = useState(libraryFilter);
const dSetFilter = useCallback(
debounce((filter: string) => {
dispatch(libraryActions.setLibraryFilter({ filter }));
}, 300),
[],
);
const onChange = useCallback(
(e) => {
const value = e.target.value;
setLocalFilter(value);
dSetFilter(value);
},
[dSetFilter, setLocalFilter],
);
useEffect(() => {
if (localFilter !== libraryFilter) {
setLocalFilter(libraryFilter);
}
}, [libraryFilter]);
return (
<div className="flex-1 flex">
<form className="w-full flex md:ml-0" action="#" method="GET">
<label htmlFor="search_field" className="sr-only">
Search library
</label>
<div className="relative w-full text-gray-400 focus-within:text-gray-600">
<div className="absolute inset-y-0 left-0 flex items-center pointer-events-none">
<SearchIcon className="h-5 w-5" />
</div>
<input
id="search_field"
name="search_field"
className="block w-full h-full pl-8 pr-3 py-2 border-transparent text-gray-900 placeholder-gray-500 focus:outline-none focus:ring-0 focus:border-transparent focus:placeholder-gray-400 sm:text-sm"
placeholder="Search your library"
type="search"
value={localFilter}
onChange={onChange}
/>{' '}
</div>
</form>
</div>
);
}
@cephalization
Copy link
Author

The first file is a stripped down example of what I thought I could do with useTransition after reading the changelog.
On reflection and re-reading the docs I realize that this is incorrect, and debounce is still the correct solution.

Posting for posterity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment