const { Provider, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
stuff: [
{
id: 1,
color: 'blue',
shape: 'square',
},
{
id: 2,
color: 'red',
shape: 'circle',
},
{
id: 3,
color: 'yellow',
shape: 'square',
},
],
};
const reducer = (state) => state;
//helper
const createFilterBy = (field, value) => (item) =>
value ? item[field] === value : true;
//selectors
const selectStuff = (state) => state.stuff;
const createSelectFiltered = (filterFn) =>
createSelector([selectStuff], (stuff) =>
stuff.filter(filterFn)
);
const createSelectByColor = (color) =>
createSelector(
[createSelectFiltered(createFilterBy('color', color))],
(x) => x
);
const createSelectByShape = (shape) =>
createSelector(
[createSelectFiltered(createFilterBy('shape', shape))],
(x) => x
);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const List = React.memo(function List({ items }) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{JSON.stringify(item)}</li>
))}
</ul>
);
});
const SelectList = React.memo(function SelectList({
label,
value,
setter,
options,
}) {
return (
<label>
{label}
<select
value={value}
onChange={({ target: { value } }) =>
setter(value === 'all' ? undefined : value)
}
>
<option value="all">all</option>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
</label>
);
});
const colors = ['blue', 'red', 'yellow'];
const shapes = ['square', 'circle'];
const App = () => {
const [color, setColor] = React.useState();
const [shape, setShape] = React.useState();
const selectByColor = React.useMemo(
() => createSelectByColor(color),
[color]
);
const selectByShape = React.useMemo(
() => createSelectByShape(shape),
[shape]
);
const byColor = useSelector(selectByColor);
const byShape = useSelector(selectByShape);
return (
<div>
<div>
<SelectList
label="color"
value={color}
setter={setColor}
options={colors}
/>
<SelectList
label="shape"
value={shape}
setter={setShape}
options={shapes}
/>
</div>
<div>
<h4>color</h4>
<List items={byColor} />
<h4>shape</h4>
<List items={byShape} />
</div>
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>