Home > OS >  in a map function, i want to set a state which let me change the background color when i click on a
in a map function, i want to set a state which let me change the background color when i click on a

Time:03-16

So here's my problem, i map some data i receive from the back, it returns a group of div, i would like to be able to click a div, change his color background and use it in total price (they're options you can choose).

i tried to put a state "clicked" which set true on click, but the state is on all element ans not the only one i just clicked. After if my state is true, i change the background color and add it to the total price (calculated in the modal in details)

 <p className="title-config">Configuration</p>
        {data &&
          data.additionalCharges.map((charges, index) => {
            // console.log("charges.map", charges);
            return (
              <div
                className={
                  clicked === true ? "clicked-config" : "unclicked-config"
                }
                key={index}
                onClick={() => setClicked(true)}
              >
                <p>{charges.title}</p>
                <p>{charges.description}</p>
                <p>
                  {charges.price.amount} {location.state.price.currency}
                </p>
              </div>
            );
          })}
      </div>
      <div className="colonne2-config">
        <div>
          <span> Total {location.state.total}</span>
          <span>{location.state.price.amount}</span>
        </div>

        <div>
          <div onClick={() => setShowModal(true)}>Voir les details du prix</div>
          <Modal
            isOpen={showModal}
            onRequestClose={() => setShowModal(false)}
            style={{
              overlay: {
                backgroundColor: "lightgrey",
                backgroundOpacity: "50%",
              },
            }}
          >
            <h1>Details du prix</h1>
            <button onClick={() => setShowModal(false)}> X </button>
          </Modal>
        </div>

CodePudding user response:

Here is a working example to achieve the desired objective:

Code Snippet

const {useState} = React;

const SomeComponent = ({data, ...props}) => {
  // the clicked is being used to achieve two goals
  // 1. track which item is clicked (ie, selected)
  // 2. update the total-price by adding / subtracting the clicked item's price
  // NOTE: This is not a good approach to employ in general. Please avoid.
  // Instead, use a separate variable to calculate the total-price.
  const [clicked, setClicked] = useState({total: 0});
  const getClass = idx => (`item ${clicked[idx] ? 'selected' : 'unselected'}`);

  return (
    <div>
      <h4>List of Items</h4>
      {
        data && Array.isArray(data) && data.map(
          ({title, description, amount}, idx) => (
            <div
              key={idx}
              onClick={() => setClicked(prev => ({
                ...prev,
                total: (
                  prev[idx] ? prev.total -  amount : prev.total    amount
                ),
                [idx]: !prev[idx]
              }))}
              class={getClass(idx)}
            >
              {title} &emsp; {description} &emsp; {amount}
            </div>
          )
        )
      }
      <br/>
      Total Price: {clicked.total}
    </div>
  );
};

const rawData = [
  {title: 'Title 00', description: 'Description 00', amount: '100'},
  {title: 'Title 01', description: 'Description 01', amount: '110'},
  {title: 'Title 02', description: 'Description 02', amount: '120'},
  {title: 'Title 03', description: 'Description 03', amount: '130'},
  {title: 'Title 04', description: 'Description 04', amount: '140'},
  {title: 'Title 05', description: 'Description 05', amount: '150'},
  {title: 'Title 06', description: 'Description 06', amount: '160'}
];

ReactDOM.render(
  <div>
    <h2>DEMO</h2>
    <SomeComponent data={rawData}/>
  </div>,
  document.getElementById('reactdiv')
);
.item {
  border: 2px solid black;
  margin-bottom: 10px;
  padding: 2px 15px;
  cursor: default;
  width: fit-content;
}

.unselected { background-color: #EEEEFF; }
.selected { background-color: #6666AA; color: white}
<div id='reactdiv'/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

Explanation

  • The clicked needs to be a data-structure that can track which of the items rendered are clicked (ie, selected) and which are not.
  • In this snippet, it is set as an object
  • For simplicity of the demo, the same clicked object serves a secondary purpose of holding the total price.
  • When user clicks on any item, it's background color changes (using getClass method)
  • And, the price of the item is added to or removed from total

Overall - this is a fairly simple, straight-forward code snippet.

CodePudding user response:

As per my understanding of the question what you can do is, add another state called divIndex and change the condition to clicked && divIndex === index or you can just remove the clicked state and only use the divIndex state also like divIndex === index.

  • Related