Redux - Selectors & Reselect
Selectors compute derived data from the store. Memoized selectors avoid recomputation unless inputs change.
Try it: Reselect memoization
View source
const { createStore } = Redux;
const { createSelector } = Reselect;
const initial = { items: Array.from({length:500}, (_,i)=>({ id:i, done:i%3===0 })) , filter:'all' };
function reducer(s=initial, a){
if (a.type==='filter/set') return { ...s, filter:a.payload };
if (a.type==='toggle') return { ...s, items: s.items.map(x => x.id===a.payload ? { ...x, done:!x.done } : x) };
return s;
}
const store = createStore(reducer);
const selectItems = s => s.items;
const selectFilter = s => s.filter;
let computeCount = 0;
const selectVisible = createSelector([selectItems, selectFilter], (items, filter) => {
computeCount++;
if (filter==='done') return items.filter(x=>x.done);
if (filter==='todo') return items.filter(x=>!x.done);
return items;
});
function render(){
const state = store.getState();
const visible = selectVisible(state);
document.getElementById('sel-out').textContent = `visible:${visible.length} computeCount:${computeCount}`;
}
store.subscribe(render); render();
// UI wiring
document.getElementById('sel-all').onclick = () => store.dispatch({type:'filter/set', payload:'all'});
document.getElementById('sel-done').onclick = () => store.dispatch({type:'filter/set', payload:'done'});
document.getElementById('sel-todo').onclick = () => store.dispatch({type:'filter/set', payload:'todo'});
document.getElementById('toggle-first').onclick = () => store.dispatch({type:'toggle', payload:0});
Syntax primer
createSelector(inputs..., resultFn)
memoizes results until inputs change.- Use small input selectors (
s => s.items
) combined by a memoized selector.