Reputation: 313
i have an issue trying to create a "typehead" funcitonality in my app, i have an "input" that listen to onChange, and that onChange is calling to a Redux reducer that search for a tag in hole store, i need to retrive all matches with my search, over here everything is ok, but when i delete my search, my hole store is equals to my filtered results, and i want that when my search is empty it returns hole my store. (gif and code)
case 'SEARCH_BY_TAG':
let tag = action.tag
let filtered = state.slice(0)
if(tag != ""){
const copied = state.filter(item => {
return item.tags.find(obj => {
if(obj.name.indexOf(tag) > -1){
return true
}
})
})
return filtered = copied.filter(Boolean)
}else{
return filtered
}
break;
Upvotes: 0
Views: 648
Reputation: 705
I think you should refactor your state to change it from this:
[ item1, item2, item3, ... ]
to this:
{
query: '',
options: [ item1, item2, item3, ... ]
}
This way you can do what @Raspo said in his answer - do the filtering of the options in your render function.
Currently when you change the text in the search field, you are dispatching this action:
{ type: 'SEARCH_BY_TAG', tag: 'new query' }
I think you should change the action name, and the reducer code, to look more like this:
// note this is almost exactly the same as the old action
{
type: 'CHANGE_AUTOCOMPLETE_QUERY',
query: 'new query'
}
and the reducer could then change to this:
case CHANGE_AUTOCOMPLETE_QUERY:
return Object.assign({}, state, {
query: action.query
})
Note that in the reducer case I just wrote, the options
part of the state isn't changed at all. It remains constant.
Now let's assume your current render function looks something like this:
const options = reduxState // not sure exactly how you get the state but whatever
return (
<div>
{options.map(option => {
<Option option={option} />
})}
</div>
)
This code relies on getting the state as an array. You could change it in the new setup to do this:
const query = reduxState.query
const options = reduxState.options.filter(item => {
return item.tags.find(obj => {
if(obj.name.indexOf(query) > -1){
return true
}
})
})
return (
<div>
{options.map(option => {
<Option option={option} />
})}
</div>
)
Upvotes: 1
Reputation: 1077
Instead of filtering things out inside your reducer, do it directly on render()
, there is nothing wrong with that.
You can still use the SEARCH_BY_TAG
action to keep track of the search keyword and use it to apply the filter when rendering your list.
Upvotes: 2