Home > Blockchain >  Is there any better way to write this react logic without having to create 3 useStates?
Is there any better way to write this react logic without having to create 3 useStates?

Time:02-06

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.

  • Related