Переменная не меняет значение React
Делаю для приложение перемотки слайдов, возникла проблема, что при установке значения хука, значение не меняется.
import React from 'react';
function Slides({slides}) {
const [index, setIndex] = React.useState(0);
const [slide, setSlide] = React.useState(slides[0]);
const [disabledButtonRestartAndPrev, SetDisabledButtonRestartAndPrev] = React.useState(true);
const [disabledButtonNext, setDisabledButtonNext] = React.useState(false);
const onCLickNext = () => {
setIndex(index + 1);
chekEnabled();
setSlide(slides[index]);
}
const onCLickPrev = () => {
setIndex(index - 1);
chekEnabled();
setSlide(slides[index]);
}
const onCLickRestart = () => {
setIndex(0);
setSlide(slides[0]);
SetDisabledButtonRestartAndPrev(true);
setDisabledButtonNext(false);
}
const chekEnabled = () => {
index === slides.length - 1 ? setDisabledButtonNext(true) : setDisabledButtonNext(false);
index > 0 ? SetDisabledButtonRestartAndPrev(false) : SetDisabledButtonRestartAndPrev(true)
}
return (
<div>
<div id="navigation" className="text-center">
<button onClick={onCLickRestart} disabled={disabledButtonRestart} data-testid="button-restart"
className="small outlined">Restart
</button>
<button onClick={onCLickPrev} disabled={disabledButtonPrevious} data-testid="button-prev"
className="small">Prev
</button>
<button onClick={onCLickNext} disabled={disabledButtonNext} data-testid="button-next"
className="small">Next
</button>
</div>
<div id="slide" className="card text-center">
<h1 data-testid="title">{slide.title}</h1>
<p data-testid="text">{slide.text}</p>
</div>
</div>
);
}
export default Slides;
При отладке в браузере при первом нажати на кнопку "Next" index так и остается = 0, при повторном нажатии уже 1, и тд. Подскажите в чем проблема?
Ответы (1 шт):
Автор решения: Nikolya Shirshov
→ Ссылка
Это связано с несколькими setState подряд, т.к. React группирует их и только потом ререндерит компонент, а состояния обновляются только после ререндера. Пример:
const onClickNext = () => {
setIndex(index + 1); // Сделали запрос на обновление index
chekEnabled();
setSlide(slides[index]); // Но т.к. компонент не ререндерился в index по прежнему 0
}
Решение 1
Можно slide и index объеденить в одно состояние, т.к. они всегда изменяются вместе. Пример:
const [state, setState] = React.useState({ index: 0, slide: slides[0] });
Решение 2 (useEffect)
import React from 'react';
function Slides({ slides }) {
const [index, setIndex] = React.useState(0);
const [slide, setSlide] = React.useState(slides[0]);
const onCLickNext = () => {
setIndex(index + 1);
};
const onCLickPrev = () => {
setIndex(index - 1);
};
const onCLickRestart = () => {
setIndex(0);
};
/** При изменении index вызывается эффект изменения слайда */
React.useEffect(() => {
setSlide(slides[index]);
}, [index]);
/** Если слайдов стало меньше, а index равен последнему элементу */
React.useEffect(() => {
const maxIndex = slides.length - 1;
if (index > maxIndex) {
setIndex(maxIndex);
}
}, [slides]);
return (
<div>
<div id="navigation" className="text-center">
<button
onClick={onCLickRestart}
disabled={index === 0} // Нет смысла в состояниях для кнопок в данном примере, т.к. они зависят только от index и slides
data-testid="button-restart"
className="small outlined"
>
Restart
</button>
<button
onClick={onCLickPrev}
disabled={index === 0}
data-testid="button-prev"
className="small"
>
Prev
</button>
<button
onClick={onCLickNext}
disabled={index >= (slides.length - 1)}
data-testid="button-next"
className="small"
>
Next
</button>
</div>
<div id="slide" className="card text-center">
<h1 data-testid="title">{slide.title}</h1>
<p data-testid="text">{slide.text}</p>
</div>
</div>
);
}
export default Slides;