javascript - Redux: Tyngre logik i Action Creators saktar ner UI? (Borde det omslutas med setTimeout()?)
Ska dyr logik i Redux Toolkit Action Creators ligga i setTimeout()?
Användningsfallet är en filtreringsruta som filtrerar data. I koden nedan finns en åtgärdsskapare som är ansvarig för att först uppdatera tillståndet för filtreringsrutan och sedan uppdatera de filtrerade uppgifterna.
När jag inte kapslar in filtreringslogiken i setTimeout finns det en märkbar fördröjning i användargränssnittet för filtreringsrutan (att ändra filtreringsorden försvåras). Är det alltså en rekommenderad praxis att lägga tyngre logik inom action creators i något som setTimeout()?
export const filteringWordsChanged = (newWords: string) => (dispatch: any, getState: any) => {
// Send Action to make sure the filter box insides are updated.
dispatch(updateFilteringWords(newWords));
let callback = () => {
let filtered = performFilteringLogic(getState(), newWords);
dispatch(updateFilteredResults(filtered));
};
// callback();
setTimeout(callback, 0);
}
Svar #1
Så jag antar att performFilteringLogic inte är async, det är bara långsamt? Min instinkt säger att detta bäst hanteras inne i komponenten med de två åtgärderna som dispatchas separat. Vi vill att ändringarna i words ska vara omedelbara, medan uppdateringen av de filtrerade resultaten kan ta lite tid (som en bisats: filtrering är vanligtvis den typ av sak som görs genom en memoiserad selector snarare än genom att lagra de filtrerade resultaten i din store).
Här anropar callbacken på input onChange-händelsen omedelbart updateFilteringWords. Det kommer att göra att variabeln words från selectorn ändras. Effekten lyssnar på förändringar i words. Om words inte är samma sträng som användes för att generera den aktuella filtered-listan, utför den den kostsamma performFilteringLogic-beräkningen och skickar resultaten med updateFilteredResults.
const MyComponent = () => {
const dispatch = useDispatch();
const state = useSelector(state => state);
const words = useSelector(state => state.something.words);
const filtered = useSelector(state => state.something.filtered);
// I would store an extra property alongside the filtered results that stores the string of words which were used to generate them
// We can use this to prevent the effect from running unecessarily, like when the component is mounted
const filteredBy = useSelector(state => state.something.filteredBy)
useEffect( () => {
// don't filter again on the same word list
if ( words !== filteredBy ) {
const filtered = performFilteringLogic(state, words);
// We would pass both the filtered results and the words so that words can be saved to `filteredBy` in the reducer
dispatch(updateFilteredResults(filtered, words));
}
}, [words]);
return (
<>
<input value={words} onChange={(e) => dispatch(updateFilteringWords(e.currentTarget.value))}/>
<SomeComponent data={filtered}/>
</>
)
}
