См. это примечание в документации:
Примечание
В отличие от метода setState
, найденного в компонентах класса, useState
не объединяет объекты обновления автоматически. Вы можете воспроизвести это поведение, объединив форму средства обновления функции с синтаксисом расширения объекта:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Другой вариант - useReducer
, который больше подходит для управления объектами состояния, содержащими несколько подзначений.
При текущем способе работы с состоянием, используя один объект для всего своего состояния, вы должны распределить другие аспекты своего состояния, просто обновляя один элемент. Так, например, вместо:
// Incorrect
setState({
films: []
});
вы должны сделать:
// Incorrect
setState(state => ({
...state,
films: []
}));
Не делать это:
// DON'T DO THIS, IT'S LIKELY TO CAUSE TROUBLE
setState({
...state,
films: []
});
Обновления состояния могут быть асинхронными и могут накапливаться. Если вы сделаете это, вы можете стереть эффект предыдущего обновления.
Но , вместо использования одного объекта состояния, я рекомендую прочитать всю эту страницу . По сути, с хуками вместо:
// Not this
const [state, setState] = useState({
films: [],
page: 1,
genres: [],
currentCategory: ""
})
вы обычно хотите это:
// This instead
const [films, setFilms] = useState([]);
const [page, setPage] = useState(1);
const [genres, setGenres] = useState([]);
const [currentCategory, setCurrentCategory] = useState("");
Затем используйте соответствующую функцию setXYZ
. Вместо setState({films: []})
вы бы сделали:
setFilms([]);
В комментарии вы сказали:
Я сделал useState для каждого элемента и, наконец, получил правильный. Моя функция увеличивает количество страниц, но я не могу получить фильмы с этих страниц.
Поскольку вы дали ему пустой массив зависимостей, ваш обратный вызов useEffect
будет запущен только один раз, когда компонент сначала создается. Если вы хотите, чтобы обратный вызов эффекта вызывал снова, когда что-то изменяется (например, если изменяется page
), добавьте это в массив зависимостей. Похоже, что getFilms
использует как page
, так и currentCategory
, поэтому вы должны включить оба из них. Я бы также сделал их параметры в getFilms
вместо того, чтобы использовать их из состояния:
useEffect(() => {
getFilms(page, currentCategory); // ***
}, [page, currentCategory]); // ***
Теперь обратный вызов будет вызываться при изменении page
или currentCategory
(но не беспокойтесь, обычно он вызывается только один раз, если вы меняете их обоих один за другим).
Вы также можете рассмотреть возможность отмены невыполненного GET
, если вы начинаете новый. (Или, как минимум, игнорируя его результат.) Подробности см. В документации ios . Из документации похоже, что в нем используется старое предложение отменяемых обещаний, которое сейчас отозвано. Вот версия getFilms
, которая принимает токен отмены:
const getFilms = (page, currentCategory, cancelToken) => {
return Axios.get(
`${baseUrlDiscover}&page=${page}&with_genres=${currentCategory}`,
{ cancelToken }
);
};
Тогда вы бы использовали его так:
useEffect(() => {
let cancel;
let cancelToken = new Axios.CancelToken(c => {
cancel = () => {
c();
c.cancelled = true;
};
});
getFilms(page, currentCategory, cancelToken)
.then(films => setFilms(films))
.catch(error => {
if (!cancel.cancelled) {
// ...handle/report error, then:
setFilms([]);
}
});
return cancel;
}, [page, currentCategory]);
Довольно неуклюжий, может быть, есть топор получше ios -specifi c way (я не использую Ax ios). FWIW, вот современная версия getFilms
с использованием fetch
и AbortSignal
:
const getFilms = (page, currentCategory, signal) => {
return fetch(
${baseUrlDiscover}&page=${page}&with_genres=${currentCategory}
, {signal}); };
Тогда вы бы использовали это так:
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
getFilms(page, currentCategory, signal)
.then(films => setFilms(films))
.catch(error => {
if (!signal.aborted) {
// ...handle/report error, then:
setFilms([]);
}
});
return () => controller.abort();
}, [page, currentCategory]);
Я рекомендую эту статью на useEffect
(на самом деле это больше, чем useEffect
, это о том, как работают функциональные компоненты, использующие хуки).