I am using reselect lib in my React project. Here is a code:
const App = () => {
// const { tickets, isFetching, error } = useSelector(({ tickets }) => tickets) // <- this works good
const { sorterTabs, selected } = useSelector(({ sorter }) => sorter)
const { isFetching } = useSelector(({ tickets }) => tickets)
const dispatch = useDispatch()
const tickets = useSelector(sorterSelector) // <- this doesn't work good
const handleSorterClick = ({ target }) => {
dispatch(getSelectedSorter(target.getAttribute('name')))
}
const renderedTickets = tickets.map((ticket) => { // <- problem: I have undefined here because selector returns undefined
const src = `http://pics.avs.io/99/36/${ticket.carrier}.png`
return (
<Ticket
key={ticket.price + ticket.segments[0].duration}
ticket={ticket}
price={ticket.price}
src={src}
segment={ticket.segments}
/>
)
}).slice(0,5)
useEffect(() => {
dispatch(fetchData())
}, [])
return (
<div className="container">
<Header />
<div className="content">
<Filter />
<div className="content__item">
<div className="content__item__sorting">
<Sorter
sorterTabs={sorterTabs}
selected={selected}
handleSorterClick={handleSorterClick}
/>
</div>
{isFetching
?
<img src={preloader} alt="preloader" />
:
<div className="content__item__tickets">
{renderedTickets}
</div>
}
</div>
</div>
</div>
)
}
Code for selector:
const allTickets = state => state.tickets.tickets // <- this gets undefined
const selected = state => state.sorter.selected
export const sorterSelector = createSelector(
[allTickets, selected],
(tickets, selec) => {
if (selec === "Самый дешевый") {
tickets.sort((a, b) => {
return a.price - b.price
})
} else {
tickets.sort((a, b) => {
return (a.segments[0].duration + a.segments[1].duration) - (b.segments[0].duration + b.segments[1].duration)
})
}
}
)
As I mentioned in the App’s code, first commented line (where I destructure the object) works good: I’m fetching tickets from the server, put them in redux state, get them in App’s component and render them.
But if I create selector by createSelector
function from ‘reselect’ lib and put it in useSelector
function like I mentioned in the code const tickets = useSelector(sorterSelector)
, I got mistake: TypeError: Cannot read property 'map' of undefined
. Tickets are not returned from the state, but state is empty. That means that fetchData
function didn’t work.
What am I doing wrong here? How to use it properly?
UPD: this doesn’t work too const tickets = useSelector((state) => sorterSelector(state))
Advertisement
Answer
All you need is proper return in selector:
export const sorterSelector = createSelector(
[allTickets, selected],
(tickets, selec) => {
if (tickets.isFetching || tickets.error) {
return []
}
if (selec === "Самый дешевый") {
return [tickets.tickets].sort((a, b) => a.price - b.price)
} else {
return [tickets.tickets].sort((a, b) => (a.segments[0].duration + a.segments[1].duration) - (b.segments[0].duration + b.segments[1].duration))
}
}
)