Home > Software engineering >  Variable not incrementing React
Variable not incrementing React

Time:12-19

I have 6 cubes displayed on the page and there is a counter. When you click on a cube, its background changes to red and the counter increases by one, but the counter does not want to increase. I always have it 1. But if you remove the setcub([...cubikinapole]) line, then the counter starts working as it should, but now the background does not change. What to do?

import "./styles.css";
import {useState} from 'react'
export default function App() {
  let [cubikinapole, setcub] = useState([
    {id:1,title:1, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/1.png", style: 'none'},
    {id:2,title:2, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/2.png" , style: 'none'},
    {id:3,title:3, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/3.png" , style: 'none'},
    {id:4,title:4, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/4.png" , style: 'none'},
    {id:5,title:5, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/5.png" , style: 'none'},
    {id:6,title:6, img:"https://www.zonkpro.ru/zonk/assets/dice/mini/6.png" , style: 'none'},
  ])
  let [count,se] = useState(0)
  function  a(el) {
    se(count  )
    el.style = 'active'
    setcub([...cubikinapole])
    console.log(count)
  }
  return (
    <div className="App">
                          {cubikinapole.length !== 0 ? 
                    cubikinapole.map((el)=>
                    <div id='cub' key={el.id} className={el.style} onClick={()=>a(el)}>
                      <img src={el.img} />
                    </div>
                    )
                    : console.log() }
    </div>
  );
}

CSS

.active{
  background-color: red;
}

CodePudding user response:

you're never supposed to change the value of a useState by the value itself, only by the setter - what you're doing where you're writing se(count ) is giving the old value of the count to se and then directly changing count by count ,

so it looks like a race condition, you can fix it by just changing it to se(count 1) and your code will run as it should

CodePudding user response:

You can try this code. count increases its value after the setCount function is executed, so you should use count to pass the increased value to the function. And you'd better use useEffect to monitor the count value.

import "./styles.css";
import { useState, useEffect } from "react";
export default function App() {
  let [cubikinapole, setCub] = useState([
    {
      id: 1,
      title: 1,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/1.png",
      style: "none"
    },
    {
      id: 2,
      title: 2,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/2.png",
      style: "none"
    },
    {
      id: 3,
      title: 3,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/3.png",
      style: "none"
    },
    {
      id: 4,
      title: 4,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/4.png",
      style: "none"
    },
    {
      id: 5,
      title: 5,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/5.png",
      style: "none"
    },
    {
      id: 6,
      title: 6,
      img: "https://www.zonkpro.ru/zonk/assets/dice/mini/6.png",
      style: "none"
    }
  ]);

  let [count, setCount] = useState(0);

  useEffect(() => {
    console.log(count);
  }, [count]);

  function a(el) {
    setCount(  count);
    el.style = "active";
    setCub([...cubikinapole]);
  }
  return (
    <div className="App">
      {cubikinapole.length !== 0
        ? cubikinapole.map((el) => (
            <div key={el.id} className={el.style} onClick={(e) => a(el)}>
              <img src={el.img} alt={el.title} />
            </div>
          ))
        : console.log()}
    </div>
  );
}

Live demo: https://codesandbox.io/s/amazing-haze-0zdb26?file=/src/App.js:0-1369

CodePudding user response:

There are a few issues. Note: I've changed the names of some variable for clarity.

  1. You can't set your counter like that. Ideally you want to take the previous state, and then update and return that. So setCount(count ) becomes setCount(prev => prev = 1).

  2. ids should be unique. If you want to uniquely identify an element you can use a data attribute, and then pick up that value in the handler.

  3. With the id in hand in your handler you should find the object in state that where the object id matches the id of the element you clicked on, and then update that. To do that make a copy of the state first, update the object, and then set the state using the changed copy.

  4. It's not really clear whether it was the background of the cube you wanted to change, or the image itself so I've just left your code as-is. For the actual image to change would be slightly more difficult.

const { useState } = React;

// For clarity I'm passing in the image
// config to the component, and then setting the
// cube state with it
function Example({ config }) {

  // Initialise the states
  const [ cubes, setCubes ] = useState(config);
  const [ count, setCount ] = useState(0);

  // When an element is clicked take the
  // id from its data set. Make a copy of the state
  // and then find the index of the object that has a
  // matching id. Then update that object with the new
  // style, and set both the cube and count states
  function handleClick(e) {
    const { id } = e.currentTarget.dataset;
    const copy = [...cubes];
    const index = copy.findIndex(cube => cube.id === Number(id));
    if (index >= 0) copy[index].style = 'active';
    setCubes(copy);
    setCount(prev => prev  = 1);
  }

  // I've added a count element here.
  // `map` over state adding the data attribute
  // to the div element.
  return (
    <div className="App">
      <div className="counter">Count: {count}</div>
      {config.map(obj => {
        const { id, style, img } = obj;
        return (
          <div
            key={id}
            data-id={id}
            className={style}
            onClick={handleClick}
          ><img src={img} />
          </div>
        );
      })}
    </div>
  );

}

const config=[{id:1,title:1,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/1.png",style:"none"},{id:2,title:2,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/2.png",style:"none"},{id:3,title:3,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/3.png",style:"none"},{id:4,title:4,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/4.png",style:"none"},{id:5,title:5,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/5.png",style:"none"},{id:6,title:6,img:"https://www.zonkpro.ru/zonk/assets/dice/mini/6.png",style:"none"}];

ReactDOM.render(
  <Example config={config} />,
  document.getElementById('react')
);
.active { background-color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

  • Related