const [currentIndex, setCurrentIndex] = useState(0);
const [previousIndex, setPreviousIndex] = useState(2);
const [nextIndex, setNextIndex] = useState(1);
const previous = () = {
const newCurrentIndex = currentIndex === 0 ? slides.length - 1 : currentIndex - 1;
setCurrentIndex(newCurrentIndex);
const newPreviousIndex = previousIndex === 0 ? slides.length - 1 : previousIndex - 1;
setPreviousIndex(newPreviousIndex);
const newNextIndex = nextIndex === 0 ? slides.length - 1 : nextIndex - 1;
setNextIndex(newNextIndex);
}
const next = () = {
const newCurrentIndex = currentIndex === slides.length - 1 ? 0 : currentIndex 1;
setCurrentIndex(newCurrentIndex);
const newPreviousIndex = previousIndex === slides.length - 1 ? 0 : previousIndex 1;
setPreviousIndex(newPreviousIndex);
const newNextIndex = nextIndex === slides.length - 1 ? 0 : nextIndex 1;
setNextIndex(newNextIndex);
}
It is used to render pictures depending on the index, the carousel displays 3 pictures at a time so I needed previous current and next index, but I don't know how to make write the logic so that I don't have to write the same thing 3 times but with different starting indexes.
CodePudding user response:
You only need to state of the current index, and you can derive the other indexes from it.
To make the index cyclic (-1 becomes 2 for example), you can use a mod
function.
const { useState } = React;
const mod = (x, y) => ((x % y) y) % y;
const Demo = ({ slides }) => {
const [currentIndex, setCurrentIndex] = useState(0);
const len = slides.length;
const previous = () => {
setCurrentIndex(c => mod(c - 1, len));
}
const next = () => {
setCurrentIndex(c => mod(c 1, len));
}
const prevIndex = mod(currentIndex - 1, len);
const nextIndex = mod(currentIndex 1, len);
return (
<div>
<button onClick={previous}>Prev</button>
<div>Prev Index: {prevIndex}</div>
<div>Current Index: {currentIndex}</div>
<div>Next Index: {nextIndex}</div>
<button onClick={next}>Next</button>
</div>
);
};
ReactDOM
.createRoot(root)
.render(<Demo slides={[1, 2, 3]} />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
CodePudding user response:
I don't think useReducer is complex enough for this use, and useReducer has some extra overhead to it, however I think you could combine your useState logic into a more complex object like
const [indexState, setIndexState] = useState({currentIndex: 0, previousIndex: 2, nextIndex: 1});
Then you can just set it like
setIndexState({currentIndex: 1, previousIndex: 0, nextIndex: 2 })
React trys to batch setStates however, this will guarentee only 1 render cycle vs your 3.