#reactjs #react-hooks #use-state
#reactjs #реагирующие хуки #use-state
Вопрос:
Я тренирую перехваты React с помощью приложения movie, и теперь я сталкиваюсь с проблемой. Когда я нажимаю кнопку в Header
компоненте, должно произойти изменение состояния путем очистки itemsList
массива. Код фактически подготовлен для Load More
кнопки, которая добавит больше элементов в этот массив, когда запрос API используется с другим компонентом (еще не представлен). Проблема в том, что массив не был очищен, и когда какая-то кнопка является клише, к ней добавляются элементы из запроса API que.
Это App.js файл
import React, { useState } from "react";
import axios from "axios";
import Header from "./Containers/Header";
export default function App() {
const [values, setValues] = useState({
msdb: "API_CODE",
page: 1,
totalPages: 0,
listType: "popular",
mode: "movie",
itemsList: [],
searchFiled: "",
loading: false,
error: false
});
const { msdb, page, totalPages, listType, mode, itemsList, searchFiled, loading, error } = values;
const modeSelection = (event) => {
let modeType = "";
let selectedMode = event.target.innerText;
console.log(selectedMode);
if (selectedMode === "Movies") {
modeType = "movie";
} else if (selectedMode === "Series") {
modeType = "tv";
}
setValues((prevValues) => {
return { ...prevValues, mode: modeType, itemsList: [] };
});
let endPoint = `https://api.themoviedb.org/3/${mode}/${listType}?api_key=${msdb}amp;page=${page}`;
fetchItems(endPoint);
};
const fetchItems = (endPoint) => {
axios
.get(endPoint)
.then((response) => {
const newItemsList = [...itemsList];
const newItems = response.data.results;
if (newItems) {
setValues((prevValues) => {
return {
...prevValues,
page: response.data.page,
itemsList: [...newItemsList, ...newItems],
loading: false,
totalPages: response.data.total_pages
};
});
}
})
.catch((error) => {
setValues({ ...values, error: true });
console.log(error);
});
};
return (
<div className="App">
<Header mode={modeSelection} />
</div>
);
}
И это Header.js файл
import React from "react";
import "./Header.css";
import { NavLink } from "react-router-dom";
export default function Header(props) {
return (
<div>
<div className="top-center">
<NavLink to="/movies" onClick={props.mode} className="ch-button">
Movies
</NavLink>
<NavLink to="/series" onClick={props.mode} className="ch-button">
Series
</NavLink>
</div>
</div>
);
}
Итак, я хотел бы, чтобы результатом было то, что при нажатии на кнопки компонента заголовка массив ItemsList должен быть очищен, и запрос API снова его заполнит. Помните, что метод axios уже подготовлен для кнопки Загрузить больше в другом компоненте, и в этом случае он добавит больше элементов в массив. Должен ли где-то быть эффект использования?
Спасибо
Ответ №1:
Проблема заключается в асинхронном характере setState . Вы правильно используете prevState для установки нового, но в ‘fetchItems’ при установке новых элементов вы получаете старые из текущего состояния, а не prevState. Таким образом, состояние еще не обновляется пустым массивом, когда вы используете его для установки новых элементов. Вы можете попробовать
if (newItems) {
setValues((prevValues) => {
return {
...prevValues,
page: response.data.page,
itemsList: [...prevState.itemsList, ...newItems],
loading: false,
totalPages: response.data.total_pages
};
});
}
Комментарии:
1. Это сработало! Зачем добавлять const modeSelection = async (событие) => {…. и ожидать setValues … не работает?
2. Это особенность Reactjs. Установка состояния всегда асинхронна, но сама функция не возвращает обещание. Так что вы не можете этого ждать.