I had a react issue in which I was trying to fetch some data using an asynchronous function that might return sooner or later, called in response to the user's keystrokes (basically a typeahead function). Since older queries might return before newer ones, I wanted to keep track of the most recently submitted query string and only update the results if this most recent query string matched the query string that had been used to call the function.
I found two ways of doing this that worked equally well, from my vantage point. The first one seemed pretty good to me:
let currentSearchInput = '';
function TypeaheadList({searchInput}) {
const [results, setResults] = React.useState([]);
React.useEffect(() => {
currentSearchInput = searchInput;
getResults().then((results) => {
if (currentSearchInput !== searchInput) return;
setResults(results);
}
}
...
}
export default TypeaheadList;
Then, I began to worry that I hadn't really ever seen this pattern before, and also remembered that react had useRef
for situations like this, so I refactored like so:
function TypeaheadList({searchInput}) {
const [results, setResults] = React.useState([]);
const currentSearchInput = React.useRef();
React.useEffect(() => {
currentSearchInput.current = searchInput;
getResults().then((results) => {
if (currentSearchInput.current !== searchInput) return;
setResults(results);
}
}
...
}
export default TypeaheadList;
My questions are the following:
- Is the first code snippet an antipattern?
- If so, why? If not, why does react provide
useRef
at all?