Home > OS >  REACT : getting error while re-rendering components using setState hook
REACT : getting error while re-rendering components using setState hook

Time:03-03

I'm trying to change an inline style property of several items that have position info stored in a useState hook as well on the style property of each item rendered. I wanted to change the CSS value of all the items except the one I clicked on. I devised a function to do so, however when I try to update the CSS value using setState, the items don't re-render and I get an error saying "discs.map is not a function". Am I using the set state hook correctly? Should i be using the setState hook for a task like this i.e animating position of items?

// Main Component

function App() {
   const [discs, setDiscs] = useState([
      { id: 1, top: 100 },
      { id: 2, top: 200 },
      { id: 3, top: 300 },
      { id: 4, top: 400 },
      { id: 5, top: 500 },
      { id: 6, top: 600 },
      { id: 7, top: 700 },
      { id: 8, top: 800 },
      { id: 9, top: 900 },
      { id: 10, top: 1000 },
      { id: 11, top: 1100 },
      { id: 12, top: 1300 }
   ])

function enlargeDisc(e, num) {
      let t = e.target
      if (t.classList.contains('active')) {
         t.classList.remove('active')
         adjustDiscPos(num, true)
      } else {
         t.classList.add('active')
         adjustDiscPos(num, false)
      }
   }

   function adjustDiscPos(n, backToOriginal) {
      console.log(discs)
      discs.forEach((disc) => {
         if (disc.id < n) {
            setDiscs(prevState =>  backToOriginal ? prevState   300 : prevState - 300)
         }
         if (disc.id > n) {
            setDiscs(prevState =>  backToOriginal ? prevState - 300 : prevState   300)
         }
      })
   }

  return (
    <div className="App">
      <div className="container">
         <div className="wrapper" style={{bottom: scroll}}>
            {discs.map((item) => (
               <div className ='disc' key={item.id} data-index={item.id} style={{top: item.top   'px'}} onClick={(e)=> enlargeDisc(e, item.id)} ></div>
            ))}
        </div>
      </div>
    </div>
  );
}

export default App;

CSS

.disc {
   position: absolute;
   transform:
      translate(-50%, -50%) rotateX(90deg) scale(1);
   width: 10em;
   height: 10em;
   transform-style: preserve-3d;
   cursor: pointer;
   background-image:
   radial-gradient(rgba(0, 0, 0, 0), rgb(22, 22, 22) 95%), 
   url('./img/cd3.png');
   background-size: 100% 100%;
   transition: all 0.5s ease-in-out; 
}

.disc.active {
   transform:
   translate(-50%, -50%) rotateX(0deg) scale(1.5);
}

CodePudding user response:

I am assuming here that it is the value of top you wish to manipulate. I am also assuming that you wish to leave the disc with id equal to n as it is. Correct me if I'm wrong.

What you need to do is to create a temporary array and add the new values to that array. Then, when that is done, you call setDiscs with the temporary array as an argument.

let tmp_discs = [];

discs.forEach((disc) => {
  if (disc.id < n) {
    tmp_discs[disc.id] = backToOriginal ? disc.top   300 : disc.top - 300;
  } else if (disc.id > n) {
    tmp_discs[disc.id] = backToOriginal ? disc.top - 300 : disc.top   300;
  } else {
    tmp_discs[disc.id] = disc.top;
  }
})

setDiscs(tmp_discs);

CodePudding user response:

In adjustDiscPos you are calling setDiscs with the value of a subtraction of an array and 300 prevState - 300.

This will push NaN to discs and hence your error.

You should compute a new array in your forEach and then call setDiscs only once.

CodePudding user response:

Building up on what Radu Dita said

In adjustDiscPos you are calling setDiscs with the value of a subtraction of an array and 300 prevState - 300. This will push NaN to discs and hence your error. You should compute a new array in your forEach and then call setDiscs only once.

What this means is that instead of using a forEach and do setDiscs for each item in the array, you're supposed to use setDiscs once (prevState is the reference to the current discs value), and do your arrayu operation on it through map or something.

function adjustDiscPos(n, backToOriginal) {
      console.log(discs)
      setDiscs(prevState => prevState.map(disc => {
         const offset = backToOriginal ? 300 : -300;
         return { id: disc.id, top: disc.id < n ? disc.top   offset : disc.top - offset };
      })

Just make sure to remember not to mutate prevState directly either since it is a reference to current state variable, but rather to use some array function which returns a new value.

  • Related