Как правильно использовать функцию createSelector (библиотека reselect) с хуком useSelector в приложении React?

Делаю проект на React. Код компонента App:

const App = () => {

  //const { tickets, isFetching, error } = useSelector(({ tickets }) => tickets)  // <- эта строка работает хорошо

  const { sorterTabs, selected } = useSelector(({ sorter }) => sorter)
  const { isFetching } = useSelector(({ tickets }) => tickets)
  const dispatch = useDispatch()
  const tickets = useSelector(sorterSelector)  // <- эта строка не работает, селектор возвращает undefined!

  const handleSorterClick = ({ target }) => {
    dispatch(getSelectedSorter(target.getAttribute('name')))
  }

  const renderedTickets = tickets.map((ticket) => {  // <-  проблема, tickets is 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>
  )
}

Код для селектора:

const allTickets = state => state.tickets
const selected = state => state.sorter.selected

export const sorterSelector = createSelector(
  [allTickets, selected],
  (tickets, selec) => {                          // <- tickets undefined!
    if (tickets.isFetching || tickets.error) {
      return []
    }
    if (selec === "Самый дешевый") {
      [...tickets.tickets].sort((a, b) => {
        return a.price - b.price
      })
    } else {
      [...tickets.tickets].sort((a, b) => {
        return (a.segments[0].duration + a.segments[1].duration) - (b.segments[0].duration + b.segments[1].duration)
      })
    }
  }
)

Первая закомментированная строка в компоненте App (где я деструктурирую объект) работает хорошо: я получаю билеты с сервера и отображаю их в компоненте. Но мне необходимо добавить сайд-эффекты в массив билетов (сортировка, фильтрация), поэтому я решил использовать селектор.

Однако, при использовании такой записи const tickets = useSelector(sorterSelector), селектор возвращает undefined (ошибка TypeError: Cannot read property 'map' of undefined). При данной записи и логике, которую я описал в sorterSelector, я даже не вижу, что функция fetchData в useEffect запускается.

Как решить эту проблему?


Ответы (1 шт):

Автор решения: rgdzv

Ошибка крылась в правильном возврате отсортированного массива в селекторе:

const allTickets = state => state.tickets
const selected = state => state.sorter.selected

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))
      })
    }
  }
)
→ Ссылка