Use reselect selector with parameters - javascript

How do I pass additional parameters to combined selectors? I am trying to
• Get data
• Filter data
• Add custom value to my data set / group data by myValue
export const allData = state => state.dataTable
export const filterText = state => state.filter.get('text')
export const selectAllData = createSelector(
allData,
(data) => data
)
export const selectAllDataFiltered = createSelector(
[ selectAllData, filterText ],
(data, text) => {
return data.filter(item => {
return item.name === text
})
}
)
export const selectWithValue = createSelector(
[ selectAllDataFiltered ],
(data, myValue) => {
console.log(myValue)
return data
}
)
let data = selectWithValue(state, 'myValue')
console.log(myValue) returns undefined

Updated: 16 February 2022
New Solution from Reselect 4.1: See detail
// selector.js
const selectItemsByCategory = createSelector(
[
// Usual first input - extract value from `state`
state => state.items,
// Take the second arg, `category`, and forward to the output selector
(state, category) => category
],
// Output selector gets (`items, category)` as args
(items, category) => items.filter(item => item.category === category)
);
// App.js
const items = selectItemsByCategory(state, 'javascript');
// Another way if you're using redux hook:
const items = useSelector(state => selectItemsByCategory(state, 'javascript'));
Updated: 6 March 2021
Solution from Reselect: See detail
// selector.js
import { createSelector } from 'reselect'
import memoize from 'lodash.memoize'
const expensiveSelector = createSelector(
state => state.items,
items => memoize(
minValue => items.filter(item => item.value > minValue)
)
)
// App.js
const expensiveFilter = expensiveSelector(state)
// Another way if you're using redux:
// const expensiveFilter = useSelector(expensiveSelector)
const slightlyExpensive = expensiveFilter(100)
const veryExpensive = expensiveFilter(1000000)
Old:
This is my approach. Creating a function with parameters and return function of reselect.
export const selectWithValue = (CUSTOM_PARAMETER) => createSelector(
selectAllDataFiltered,
(data) => {
console.log(CUSTOM_PARAMETER)
return data[CUSTOM_PARAMETER]
}
)
const data = selectWithValue('myValue')(myState);

Here's one with the latest useSelector hook.
The important thing is to get the parameter from the input selector. The input selector's second parameter is how we get it.
Here's how the selector would look,
const selectNumOfTodosWithIsDoneValue = createSelector(
(state) => state.todos,
(_, isDone) => isDone, // this is the parameter we need
(todos, isDone) => todos.filter((todo) => todo.isDone === isDone).length
)
And here's how we extract values with the useSelector hook,
export const TodoCounterForIsDoneValue = ({ isDone }) => {
const NumOfTodosWithIsDoneValue = useSelector((state) =>
selectNumOfTodosWithIsDoneValue(state, isDone)
)
return <div>{NumOfTodosWithIsDoneValue}</div>
}
Also, keep, the second parameter (isDone) as primitive values (string, number etc.) as much as possible.
Because, reselect, only runs the output selector when the input selector value changes.
This change is checked via shallow comparison, which will always be false for reference values like Object and Array.
References:
https://react-redux.js.org/next/api/hooks#using-memoizing-selectors
https://flufd.github.io/reselect-with-multiple-parameters/
https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/

The answer to your questions is detailed in an FAQ here: https://github.com/reactjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument
In short, reselect doesn't support arbitrary arguments passed to selectors. The recommended approach is, instead of passing an argument, store that same data in your Redux state.

what about returning a function from selector? getFilteredToDos is an example for that
// redux part
const state = {
todos: [
{ state: 'done', text: 'foo' },
{ state: 'time out', text: 'bar' },
],
};
// selector for todos
const getToDos = createSelector(
getState,
(state) => state.todos,
);
// selector for filtered todos
const getFilteredToDos = createSelector(
getToDos,
(todos) => (todoState) => todos.filter((toDo) => toDo.state === todoState);
);
// and in component
const mapStateToProps = (state, ownProps) => ({
...ownProps,
doneToDos: getFilteredToDos()('done')
});

This is covered in the reselect docs under Accessing React Props in Selectors:
import { createSelector } from 'reselect'
const getVisibilityFilter = (state, props) =>
state.todoLists[props.listId].visibilityFilter
const getTodos = (state, props) =>
state.todoLists[props.listId].todos
const makeGetVisibleTodos = () => {
return createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_COMPLETED':
return todos.filter(todo => todo.completed)
case 'SHOW_ACTIVE':
return todos.filter(todo => !todo.completed)
default:
return todos
}
}
)
}
export default makeGetVisibleTodos
const makeMapStateToProps = () => {
const getVisibleTodos = makeGetVisibleTodos()
const mapStateToProps = (state, props) => {
return {
todos: getVisibleTodos(state, props)
}
}
return mapStateToProps
}
In this case, the props passed to the selectors are the props passed to a React component, but the props can come from anywhere:
const getVisibleTodos = makeGetVisibleTodos()
const todos = getVisibleTodos(state, {listId: 55})
Looking at the types below for Reselect:
export type ParametricSelector<S, P, R> = (state: S, props: P, ...args: any[]) => R;
export function createSelector<S, P, R1, T>(
selectors: [ParametricSelector<S, P, R1>],
combiner: (res: R1) => T,
): OutputParametricSelector<S, P, T, (res: R1) => T>;
We can see there isn't a constraint on the type of props (the P type in ParametricSelect), so it doesn't need to be an object.

Another option:
const parameterizedSelector = (state, someParam) => createSelector(
[otherSelector],
(otherSelectorResult) => someParam + otherSelectorResult
);
And then use like
const mapStateToProps = state => ({
parameterizedSelectorResult: parameterizedSelector(state, 'hello')
});
I am not sure about memoization/performance in this case though, but it works.

Related

I'm trying to filter an array of Objects simultaneosly by number and by string value

i have a little problem in my App !
it's a simple App that shows some restaurant tables and let you filter these tables by number of people eating (capacity) and the preferred place (Inside, Patio, Bar)
I have a problem specifically with this filter functionality:
i'm able to filter the tables by Place, but when i try to simultaneosly filter the Tables by Capacity it won't work (it'll forget the Place filter, and just filter them by Capacity).
I'll explain the user flow i used:
I click on the Place select and choose the option 'Patio'
At this point 2 tables are showed; one is for 5 people, the other for 9 people
i click on the Capacity filter, choosing a table for 9 persons.
the App will forget the 'Patio' value and it'll also show a table with Location ' Bar' (and that's the part i'm trying to fix, i want the App to remember 'Patio' and only showing that one)
const defaultState : any = {
tables: [],
tablesFiltered: [],
bookings: [],
error: null,
loading: false,
}
case FILTER_TABLE:
return {
...state,
tablesFiltered: action.payload,
}
this is my action
export const filterTables = (filteredTable: tableI[]) => {
return (dispatch: (arg0: { type: string; payload?: unknown; }) => void) =>
dispatch({type: FILTER_TABLE, payload: filteredTable})
}
finally, the component where the logic of the filter is:
TableFilter.tsx
import { Form } from 'react-bootstrap';
import { useSelector, useDispatch } from 'react-redux';
import { filterTables } from '../../store/actions';
import { tableI } from '../../Interfaces';
const TableFilter: React.FC = () => {
const tables: tableI[] = useSelector((state: any) => state.tables.tables);
const dispatch = useDispatch();
const handleChange = (event: any) => {
const locationFilter: string = event.target.value;
const capacityFilter: any = event.target.value;
// console.log(typeof capacityFilter);
const filteredArr = tables.filter(
(table) => table.location === locationFilter
);
// console.log(filteredArr);
dispatch(filterTables(filteredArr));
};
const changeCapacity = (event: any) => {
// const locationFilter: string = event.target.value;
const capacityFilter: any = event.target.value;
// console.log(typeof capacityFilter);
const filteredArr = tables.filter(
(table) => table.capacity >= Number.parseInt(capacityFilter)
);
// console.log(filteredArr);
dispatch(filterTables(filteredArr));
};
const locations: string[] = tables.map((table) => table.location);
const capacity: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const uniqueLocations = [...new Set(locations)];
return (
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Select a table</Form.Label>
<Form.Control
onChange={handleChange}
as="select"
aria-label="form-select-location"
>
<option>Select your table's location</option>
{uniqueLocations &&
uniqueLocations.map((location: string, index: number) => (
<option aria-label="location" key={index} value={location}>
{location}
</option>
))}
</Form.Control>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Select the capacity of your table</Form.Label>
<Form.Control
onChange={changeCapacity}
as="select"
aria-label="form-select-capacity"
>
<option>Number of persons sitting </option>
{capacity &&
capacity.map((capacity: number, index: number) => (
<option aria-label="capacity" key={index} value={capacity}>
{capacity}
</option>
))}
</Form.Control>
</Form.Group>
</Form>
);
};
export default TableFilter;
here's my GitHub repo:
https://github.com/miki-miko/booking-system-testing
You could take an array of all filters and filter the data by all filters, you actually have.
For example take two filters, like
capacity = n => ({ capacity }) => capacity >= n;
place = p => ({ place }) => place === p;
Then put them ino an array. It does not matter, if you use only one or more, if necessary.
filters = [
capacity(2),
place('Inside')
]
As result, it returns objects where all filters return true, or at least a truthy return value.
This one with Array#every returns the objects where all conditions are true.
result = data.filter(o => filters.every(fn => fn(o))); // all
If only one constraint has to be true, take Array#some instead.
result = data.filter(o => filters.some(fn => fn(o))); // exists
You should filter the data in your selector since it is derived data and you should not store such data in your redux state. Here is a simple example of how you could do this:
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const initialState = {
tables: ['A', 'B', 'C', 'D', 'E'].flatMap((place) =>
[...new Array(5)].map((_, index) => ({
place,
capacity: index + 1,
}))
), //not sure if filter needs to be here, is is shared
// by multiple components in your application?
filter: {
capacity: 'all',
place: 'all',
},
};
//action types
const SET_FILTER = 'SET_FILTER';
//action creators
const setFilter = (key, value) => ({
type: SET_FILTER,
payload: { key, value },
});
const reducer = (state, { type, payload }) => {
if (type === SET_FILTER) {
const { key, value } = payload;
return {
...state,
filter: {
...state.filter,
[key]: value,
},
};
}
return state;
};
//selectors
const selectTables = (state) => state.tables;
const selectFilter = (state) => state.filter;
const selectPlaces = createSelector(
[selectTables],
(tables) => [...new Set(tables.map(({ place }) => place))]
);
const selectCapacities = createSelector(
[selectTables],
(tables) => [
...new Set(tables.map(({ capacity }) => capacity)),
]
);
//return true if value is all, this is specific to the filer value
// if the value is "all" then return true
//When passing a function to this it returns a function that takes a value
// when calling that function with a value it returns a function that
// takes an item
const notIfAll = (fn) => (value) => (item) =>
value === 'all' ? true : fn(value, item);
//specific filter
const capacityBiggerThan = notIfAll(
//could do more abstraction here with getProp, and re usable compare
// functions but leave this out for simplicity
(value, item) => item.capacity >= Number(value)
);
const isPlace = notIfAll(
(value, item) => value === item.place
);
//Apply multiple filter functions, it receives an array of filter functions
// and returns a function that receives an item as parameter, when the item
// is passed to this function it will call all filter functions passing this item
const mergeFilters = (filterFunctions) => (item) =>
filterFunctions.every((filterFunction) =>
filterFunction(item)
);
//select filtered data
const selectFilterData = createSelector(
[selectTables, selectFilter],
(tables, { place, capacity }) => {
return tables.filter(
mergeFilters([
isPlace(place),
capacityBiggerThan(capacity),
])
);
}
);
//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 FilterSelect = React.memo(function FilterSelect({
filterKey,
value,
values,
}) {
const dispatch = useDispatch();
return (
<select
value={value}
onChange={(e) =>
dispatch(setFilter(filterKey, e.target.value))
}
>
<option value="all">all</option>
{values.map((place) => (
<option key={place} value={place}>
{place}
</option>
))}
</select>
);
});
const App = () => {
const { capacity, place } = useSelector(selectFilter);
const places = useSelector(selectPlaces);
const capacities = useSelector(selectCapacities);
const filterData = useSelector(selectFilterData);
return (
<div>
<FilterSelect
filterKey="place"
value={place}
values={places}
/>
<FilterSelect
filterKey="capacity"
value={capacity}
values={capacities}
/>
<div>
<h1>result</h1>
<pre>
{JSON.stringify(filterData, undefined, 2)}
</pre>
</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>
The code may be confusing since there are functions that get a function passed to it and return a function that when called with a value will return yet another function. You could rewrite the filter in the following way but it would not be re usable and more difficult to extend:
const selectFilterData = createSelector(
[selectTables, selectFilter],
(tables, { place, capacity }) => {
//just put all logic in one function, easier to read but repeating logic
// and more difficult to maintain if many values are used or rules change
return tables.filter((item) => {
const placeFilter =
place === 'all' ? true : item.place === place;
const capacityFilter =
capacity === 'all'
? true
: item.capacity >= Number(capacity);
return placeFilter && capacityFilter;
});
}
);

Redux Reselect not updating when I compose?

I have a Redux Reselect selector that works fine:
// in reselect1.js
const getInputs = state => state.inputs;
export default createSelector(
getInputs,
inputs => {
const { thing } = inputs;
const items = inputs.items
.map(item => item.text)
.filter(item => item);
return {
thing,
items
};
},
);
In another selector it works if I repeat the logic to get the inputs without IDs in inputsWithoutIds:
// in reselect2.js
const inputsWithoutIds = state => {
const { thing } = state.inputs;
const items = state.inputs.items
.map(item => item.text)
.filter(item => item);
return {
thing,
items
};
};
const getSaved = state => state.saved;
export default createSelector(
getSaved,
inputsWithoutIds,
(saved, inputs) => {
const isSaved = saved.filter(saved => {
return _isEqual(saved, inputs);
}).length;
return {
isSaved,
};
},
);
However if I try to reuse my first selector then when state.inputs.items changes the new value is not picked up. So the value of isSaved doesn't change when it should.
// in reselect2.js
import inputsWithoutIds from './reselect1'
const getSaved = state => state.saved;
export default createSelector(
getSaved,
inputsWithoutIds,
(saved, inputs) => {
const isSaved = saved.filter(saved => {
return _isEqual(saved, inputs);
}).length;
return {
isSaved,
};
},
);
I can see in the docs that these functions are composable so Im not sure what I'm doing wrong? https://github.com/reduxjs/reselect

How to correctly use a curried selector function with react-redux's useSelector hook?

I am using react-redux with hooks, and I need a selector that takes a parameter that is not a prop. The documentation states
The selector function does not receive an ownProps argument. However,
props can be used through closure (see the examples below) or by using
a curried selector.
However, they don't provide an example. What is the proper way to curry as described in the docs?
This is what I've done and it seems to work, but is this right? Are there implications from returning a function from the useSelector function (it seems like it would never re-render?)
// selectors
export const getTodoById = state => id => {
let t = state.todo.byId[id];
// add display name to todo object
return { ...t, display: getFancyDisplayName(t) };
};
const getFancyDisplayName = t => `${t.id}: ${t.title}`;
// example component
const TodoComponent = () => {
// get id from react-router in URL
const id = match.params.id && decodeURIComponent(match.params.id);
const todo = useSelector(getTodoById)(id);
return <span>todo.display</span>;
}
When the return value of a selector is a new function, the component will always re-render on each store change.
useSelector() uses strict === reference equality checks by default, not shallow equality
You can verify this with a super simple selector:
const curriedSelector = state => () => 0;
let renders = 0;
const Component = () => {
// Returns a new function each time
// triggers a new render each time
const value = useSelector(curriedSelector)();
return `Value ${value} (render: ${++renders})`;
}
Even if the value is always 0, the component will re-render on each store action since useSelector is unaware that we're calling the function to get the real value.
But if we make sure that useSelector receives the final value instead of the function, then the component only gets rendered on real value change.
const curriedSelector = state => () => 0;
let renders = 0;
const Component = () => {
// Returns a computed value
// triggers a new render only if the value changed
const value = useSelector(state => curriedSelector(state)());
return `Value ${value} (render: ${++renders})`;
}
Conclusion is that it works, but it's super inefficient to return a new function (or any new non-primitives) from a selector used with useSelector each time it is called.
props can be used through closure (see the examples below) or by using a curried selector.
The documentation meant either:
closure useSelector(state => state.todos[props.id])
curried useSelector(state => curriedSelector(state)(props.id))
connect is always available, and if you changed your selector a little, it could work with both.
export const getTodoById = (state, { id }) => /* */
const Component = props => {
const todo = useSelector(state => getTodoById(state, props));
}
// or
connect(getTodoById)(Component)
Note that since you're returning an Object from your selector, you might want to change the default equality check of useSelector to a shallow equality check.
import { shallowEqual } from 'react-redux'
export function useShallowEqualSelector(selector) {
return useSelector(selector, shallowEqual)
}
or just
const todo = useSelector(state => getTodoById(state, id), shallowEqual);
If you're performing costly computations in the selector or the data is deeply nested and performance becomes a problem, take a look at Olivier's answer which uses memoization.
Here is a solution, it uses memoïzation to not re-render the component on each store change :
First I create a function to make selectors, because the selector depends on the component property id, so I want to have a new selector per component instances.
The selector will prevent the component to re-render when the todo or the id prop hasn't changed.
Lastly I use useMemo because I don't want to have more than one selector per component instance.
You can see the last example of the documentation to have more information
// selectors
const makeGetTodoByIdSelector = () => createSelector(
state => state.todo.byId,
(_, id) => id,
(todoById, id) => ({
...todoById[id],
display: getFancyDisplayName(todoById[id])
})
);
const getFancyDisplayName = t => `${t.id}: ${t.title}`;
// example component
const TodoComponent = () => {
// get id from react-router in URL
const id = match.params.id && decodeURIComponent(match.params.id);
const getTodoByIdSelector = useMemo(makeGetTodoByIdSelector, []);
const todo = useSelector(state => getTodoByIdSelector(state, id));
return <span>todo.display</span>;
}
Yes, it is how it's done, simplified example:
// Curried functions
const getStateById = state => id => state.todo.byId[id];
const getIdByState = id => state => state.todo.byId[id];
const SOME_ID = 42;
const TodoComponent = () => {
// id from API
const id = SOME_ID;
// Curried
const todoCurried = useSelector(getStateById)(id);
const todoCurried2 = useSelector(getIdByState(id));
// Closure
const todoClosure = useSelector(state => state.todo.byId[id]);
// Curried + Closure
const todoNormal = useSelector(state => getStateById(state)(id));
return (
<>
<span>{todoCurried.display}</span>
<span>{todoCurried2.display}</span>
<span>{todoClosure.display}</span>
<span>{todoNormal.display}</span>
</>
);
};
Full example:
This is helper-hook useParamSelector for TypeScript, which implements the official approach of Redux Toolkit.
Hook implementation:
// Define types and create new hook
export type ParametrizedSelector<A, R> = (state: AppState, arg: A) => R;
export const proxyParam: <T>(_: AppState, param: T) => T = (_, param) => param;
export function useParamSelector<A, R>(
selectorCreator: () => ParametrizedSelector<A, R>,
argument: A,
equalityFn: (left: R, right: R) => boolean = shallowEqual
): R {
const memoizedSelector = useMemo(() => {
const parametrizedSelector = selectorCreator();
return (state: AppState) => parametrizedSelector(state, argument);
}, [typeof argument === 'object' ? JSON.stringify(argument) : argument]);
return useSelector(memoizedSelector, equalityFn);
}
Create parametrized selector:
export const selectUserById = (): ParametrizedSelector<string, User> =>
createSelector(proxyParam, selectAllUsers, (id, users) => users.find((it) => it.id === id));
And use it:
const user = useParamSelector(selectUserById, 1001); // in components
const user = selectUserById()(getState(), 1001); // in thunks
You can also use it hook with selectors created with reselect's createSelector.

Undefined State Reselect Js

I am getting the following error: substate is undefined. However, I am not sure why substate would be undefined in my selector. Could someone please help me figure out what might be going wrong?
Selector:
import { createSelector } from 'reselect';
/**
* Direct selector to the organization state domain
*/
const selectOrganizationDomain = () => (state) => state.get('organization');
/**
* Other specific selectors
*/
/**
* Default selector used by organization
*/
const selectOrganization = () => createSelector(
selectOrganizationDomain(),
(substate) => substate.toJS()
);
const selectChanges = () => createSelector(
selectOrganization(),
(substate) => substate.get('changes')
)
export default selectOrganization;
export {
selectOrganizationDomain,
selectChanges
};
Your selectOrganizationDomain should be a function that returns .get('organization') on the state:
const selectOrganizationDomain = state => state.get('organization');
Your composed selectors should be the result of the invocation of createSelector, with the other selector functions passed in as arguments to createSelector:
const selectOrganization = createSelector(
selectOrganizationDomain,
substate => substate.toJS()
);
const selectChanges = createSelector(
selectOrganization,
substate => substate.get('changes')
);
The problem is your .toJS() in selectOrganization. I suppose organization in your state tree is immutable. It transforms your immutable object into a regualr JS object. For a regular object the get function is not defined.
Just get rid of selectOrganization and try selectChanges as:
const selectChanges = () => createSelector(
selectOrganizationDomain(),
(substate) => substate.get('changes')
)
I think createSelector is expecting you to pass a selctor for the first argument, not the result of calling a selector:
const selectChanges = () => createSelector(
selectOrganization, // no ()
(substate) => substate.get('changes')
)
I figured out the problem. In my routes.js, I forgot to inject my reducer/other modules. This was fixed with the following:
{
path: '/org',
name: 'organization',
getComponent(nextState, cb) {
const importModules = Promise.all([
System.import('containers/Organization/reducer'),
System.import('containers/Organization/sagas'),
System.import('containers/Organization'),
]);
const renderRoute = loadModule(cb);
importModules.then(([reducer, sagas, component]) => {
injectReducer('organization', reducer.default);
injectSagas(sagas.default);
renderRoute(component);
});
importModules.catch(errorLoading);
},
},

React filtering action not working

Given a currentUser with an id, and a database of 'events' created by various users, I am trying to fetch a filtered list of events that include only events created by the current user, in other words, their events.
My plan of attack was to make a piece of the state a 'filter' which would be updated depending on various things, but right now I am having trouble even getting the most basic filter to work.
The error always occurs within the function immediately below this paragraph. I have gotten an error staying "currentUser" is undefined, or that "author_id" is undefined or "cannot read property author_id or undefined."
currentUser is defined on the store when I checked with getState.
filterMyEvents() {
let cid = currentUser.id
let e = this.props.events
let myEventsFilter = (events, id) => {
debugger
(cid === e[id].author_id)
}
myEventsFilter = myEventsFilter.bind(null, this.props.events)
this.props.updateFilter(myEventsFilter);
}
The filtering takes place in Selector.js
export const allEventsByFilter = (events, filter) => {
if (filter) {
return Object.keys(events).filter(filter);
} else {
return events;
}
}
User Container:
const mapStateToProps = (state) => ({
currentUser: state.session.currentUser,
requestEvents: requestEvents,
events: allEventsByFilter(state.events, state.filter)
});
const mapDispatchToProps = (dispatch) => ({
requestEvents: () => { dispatch(requestEvents()) },
updateFilter: (filter) => dispatch(updateFilter(filter))
})
Filter actions:
export const FilterConstants = {
UPDATE_FILTER: "UPDATE_FILTER"
};
export const updateFilter = (filter) => ({
type: FilterConstants.UPDATE_FILTER,
filter
});
Filters reducer
const _defaultFilters = () => {
return true;
}
const FiltersReducer = function(state = null, action){
if (action.type === FilterConstants.UPDATE_FILTER){
// const newFilter = {[action.filter]: action.value};
return action.filter;
} else {
return state;
}
};

Categories

Resources