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)) } } )