Swapping React components within a list: How to easily change classes

For my latest project, I am building a straightforward ecommerce website. One of the key features on the product page is the ability for users to select different attributes such as sizes and colors. These options are represented by clickable divs that pull data from GraphQl and are then dynamically generated onto the DOM using a map function.

return (
      <div className="attribute-container">
        <div className="attribute">{attribute.id.toUpperCase()}:</div>
        <div className="attribute-buttons">
          {attribute.items.map((item) => {
            if (type === "Color") {
              return (
                <AttributeButton
                  key={item.id}
                  className="color-button"
                  style={{ backgroundColor: item.value }}
                  onClick={() => addAtribute({type: type, value: item.value })}/>

              );
            }
            return (
              <AttributeButton
                key={item.id}
                className="size-button"
                size={item.value}
                onClick={() => addAtribute({ type: type, value: item.value })}
              />
            );
          })}
        </div>
      </div>
    );

I have imported an external component and have implemented logic to style the buttons differently based on their attribute type, specifically checking if the attribute's type is Color before rendering them with custom styling.

The challenge I am currently facing is ensuring that when a user clicks on one attribute button, its style changes, while also toggling back to the default style when another button is selected. Implementing the onClick functionality to change styles initially was simple, but managing the behavior to ensure only one button appears clicked at a time has proven to be more complex.

Below is the code snippet for the AttributeButton component:

class Button extends PureComponent {

  constructor(props){
    super(props);
    this.state = {
      selected: false,
    }
  }

  render() {
    return (
      <div
        className={ !this.state.selected ? this.props.className : "size-selected "+this.props.className}
        style={this.props.style}
        onClick={() => {this.props.onClick(); this.setState({selected: !this.state.selected}) }}
      >
        {this.props.size}
      </div>
    );
  }
}

export default Button;

PS - I am required to use class components for this project, despite it not being my preferred choice.

Answer №1

It is recommended to maintain the state selected outside of the <Button> component and pass it as a prop instead. Consider updating your code as follows:

selectHandler = (button) => {
  const isSelected = this.state.selected === button;
  this.setState({ selected: isSelected ? null : button });
};

render() {
  return (
    <>
      <Button
        isSelected={this.state.selected === "ColorButton"}
        onClick={() => this.selectHandler("ColorButton")}
      />

      <Button
        isSelected={this.state.selected === "SizeButton"}
        onClick={() => this.selectHandler("SizeButton")}
      />
    </>
  );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing Next.js to Import a Function from a Path Stored within an Environment Variable

I'm having trouble importing a function whose path is stored in an environment variable Current import statement: import { debug } from '../lib/site-A/utils' Expected import statement: import { debug } from process.env.DEBUG_PATH In my ...

Error uploading file to Amazon S3: Node.js issue

I encounter a problem while trying to upload a file to Amazon S3. The provided code is: const s3 = require('s3'); const client = s3.createClient({ maxAsyncS3: 100, s3RetryCount: 3, s3RetryDelay: 30 ...

The two-word string is failing to pass through the query string

I've been working on passing multiple values through the query string. So far, I have successfully passed single-word values to a PHP page using jQuery. However, I encountered an issue when trying to pass a user's name like "Vishal Deb" as it onl ...

TypeScript will show an error message if it attempts to return a value and instead throws an

Here is the function in question: public getObject(obj:IObjectsCommonJSON): ObjectsCommon { const id = obj.id; this.objectCollector.forEach( object => { if(object.getID() === id){ return object; } }); throw new Erro ...

Implementing a class addition on focus event using Angular 2

Currently, I am in the process of upgrading an Angular 1 application to Angular 2 and encountering an issue with one of my existing directives. The task at hand is straightforward. When an input field is focused, a class should be added (md-input-focus) a ...

Setting focus on an input within a hierarchical tree structure using ReactJS

Currently, I have a deep tree structure implemented in ReactJS that is endless. Each node in the tree follows this model: const tree = { id:"x", name: "node 1", children : [ { id:"y", name:"sub node 1", children : [] ...

Import failures in Three.js could be attributed to potential issues with Webpack

Please note: I am utilizing create-react-app along with three.js v0.99.0. In my current project, I am faced with the challenge of importing specific modules from three.js to avoid bundling the entire library, which results in a large uncompressed file siz ...

Retain values of JavaScript variables acquired by their IDs even after a page refresh

I have a JavaScript function that retrieves HTML input values and inserts them into a table. However, when I refresh the page, those values are reset to null. How can I prevent this and keep the values visible after a refresh? I believe setting and getting ...

Issue with API causing Redux initial state problems

One issue I am facing is with fetching all products from the database and setting them into the Redux initial state. I created an action called SET_PRODUCTS_LIST where I pass the fetched products as payload in the component (I am using next js). Everything ...

When registering the onHardwareBackButton event in Ionic, the back button continues to successfully navigate to the previous page

I recently started working with Ionic and encountered an issue with the onHardwareBackButton event. The event is functioning properly and directing me to the register function, but even after going to the register function, it still navigates back to the p ...

Displaying various Ajax html responses

The function $('.my-button').click(function(e) is designed to display the output of the MySQL query in display.php, presented in HTML format. While it functions correctly, since each button is looped for every post, the script only works for the ...

Make sure to wait for the VueX value to be fully loaded before loading the component

Whenever a user attempts to directly navigate and load a component URL, a HTTP call is initiated within my Vuex actions. This call will set a value in the state once it has been resolved. I am looking to prevent my component from loading until the HTTP ca ...

Can we find a method to decrease this data usage?

I'm struggling to phrase my question, so here's a visual representation: I have developed a card browsing React web application that downloads 50mb of images lazily when a user visits the page. The actual app is only 1mb in size. These images a ...

How can I pass an object into EJS templates from views in Express 3.x?

Currently, I am utilizing ejs templates in combination with node.js and express 3.x. Is there a way to display the data object that is passed into the view? Can it be achieved similar to this example in index.ejs: <%= dump(session) %> ...

What advantages does utilizing an angular directive provide in the context of a comment?

Up to now, I have primarily used Directives in the form of Elements or Attributes. Is the Comment style directive simply a matter of personal preference for style? app.directive('heading', [function () { return { replace: true, ...

Having received a status code of 200 in Flask WebApp, I am still unable to access the page

Currently in the process of developing a webapp using Flask, I have created the homepage where users are required to input their phone number and password. Once entered, the system will send an OTP to the provided phone number. When clicking the signup bu ...

Can you describe the general structure of a favorite/star feature similar to Gmail's implementation?

Let me start by outlining the current tech stack we're utilizing, which includes AWS ELB EC2 instance with NodeJS, Restify, and other libraries for the backend, connected to DynamoDB. On the front-end, we have React with Redux. My goal is to implemen ...

The AngularJS factory does not hold on to its value

I have developed a basic factory to store a value from my authService: app.factory("subfactory", function() { var subValue = {}; return { set: set, get: get }; functi ...

perfecting the styling of a tab management system

For reference, please check out the following link: http://jsfiddle.net/XEbKy/3/ In my design, I have organized two layers of tabs. The top layer consists of two tabs while the bottom layer has three tabs. My goal is to have all these tabs neatly enclosed ...

Transferring items between containers with stylish animations in AngularJS

Two of my divs have different contents, with one initially empty and the other filled with items. By clicking on an item in the first list, I want to transfer it over to the second list through a visual animation that implies movement from right to left. W ...