Получать данные с помощью пользовательского обработчика React - PullRequest
3 голосов
/ 07 марта 2020

Я новичок ie в React, но я разрабатываю приложение, которое загружает некоторые данные с сервера, когда пользователь открывает приложение. Приложение. js рендер этого AllEvents. js компонент:

const AllEvents = function ({ id, go, fetchedUser }) {
    const [popout, setPopout] = useState(<ScreenSpinner className="preloader" size="large" />)
    const [events, setEvents] = useState([])
    const [searchQuery, setSearchQuery] = useState('')
    const [pageNumber, setPageNumber] = useState(1)

    useEvents(setEvents, setPopout) // get events on the main page

    useSearchedEvents(setEvents, setPopout, searchQuery, pageNumber)

    // for ajax pagination
    const handleSearch = (searchQuery) => {
        setSearchQuery(searchQuery)
        setPageNumber(1)
    }

    return(
        <Panel id={id}>
            <PanelHeader>Events around you</PanelHeader>
            <FixedLayout vertical="top">
                <Search onChange={handleSearch} />
            </FixedLayout>
            {popout}
            {
                <List id="event-list">
                    {
                        events.length > 0
                    ?
                        events.map((event, i) => <EventListItem key={event.id} id={event.id} title={event.title} />)
                    :
                        <InfoMessages type="no-events" />
                    }
                </List>
            }
        </Panel>
    )
}

export default AllEvents

useEvents () - это пользовательский хук в EventServerHooks. js файл. EventServerHooks предназначен для инкапсуляции различных ajax запросов. (Как вспомогательный файл, чтобы сделать AllEvents. js чище) Вот оно:

function useEvents(setEvents, setPopout) {
    useEffect(() => {
        axios.get("https://server.ru/events")
            .then(
                (response) => {
                    console.log(response)
                    console.log(new Date())
                    setEvents(response.data.data)
                    setPopout(null)
                },
                (error) => {
                    console.log('Error while getting events: ' + error)
                }
            )
    }, [])

    return null
}

function useSearchedEvents(setEvents, setPopout, searchQuery, pageNumber) {
    useEffect(() => {
        setPopout(<ScreenSpinner className="preloader" size="large" />)
        let cancel
        axios({
            method: 'GET',
            url: "https://server.ru/events",
            params: {q: searchQuery, page: pageNumber},
            cancelToken: new axios.CancelToken(c => cancel = c)
        }).then(
            (response) => {
                setEvents(response.data)
                setPopout(null)
            },
            (error) => {
                console.log('Error while getting events: ' + error)
            }
        ).catch(
            e => {
                if (axios.isCancel(e)) return
            }
        )

        return () => cancel()
    }, [searchQuery, pageNumber])

    return null
}

export { useEvents, useSearchedEvents }

А вот маленький компонент InfoMessages из первого списка кода, который отображает сообщение " Нет результатов ", если массив событий пуст:

const InfoMessages = props => {
    switch (props.type) {
        case 'no-events':
            {console.log(new Date())}
            return <Div className="no-events">No results :(</Div>
        default:
            return ''
    }
}

export default InfoMessages

Так что моя проблема в том, что события периодически загружаются и периодически не появляются после открытия приложения. Как вы можете видеть в коде, я помещаю консольный журнал в useEvents () и в InfoMessages , поэтому при его отображении это выглядит так: регистрирует, если отображаются события и само приложение

И если оно не отображается, оно выглядит так: регистрирует, если события не отображаются , и само приложение

Я должен отметить, что данные с сервера загружаются идеально в обоих случаях, поэтому я совершенно не представляю, почему они ведут себя по-разному с одним и тем же кодом. Чего мне не хватает?

1 Ответ

1 голос
/ 09 марта 2020

Не передавайте ловушку пользовательской ловушке: пользовательские ловушки должны быть отделены от определенного компонента c и, возможно, использованы повторно. Кроме того, ваши пользовательские хуки всегда возвращаются null, и это неправильно. Но ваш код довольно легко исправить.

В вашем основном компоненте вы можете извлекать данные с помощью пользовательского хука, а также получать состояние загрузки, например:

function Events () {
  const [events, loadingEvents] = useEvents([])

  return loadingEvents ? <EventsSpinner /> : <div>{events.map(e => <Event key={e.id} title={e.title} />}</div>
}

В вашем Пользовательский хук вы должны вернуть внутреннее состояние. Например:

function useEvents(initialState) {
  const [events, setEvents] = useState(initialState)
  const [loading, setLoading] = useState(true)

  useEffect(function() {
    axios.get("https://server.ru/events")
            .then(
                (res) => {
                    setEvents(res.data)
                    setLoading(false)
                }
            )
  }, [])

  return [events, loading]
}

В этом примере пользовательский хук возвращает массив, потому что нам нужны два значения, но вы также можете вернуть объект с двумя парами ключ / значение. Или простая переменная (например, только массив events, если вам не нужно состояние loading), используйте его так:

const events = useEvents([])
...