Creating a React component for a button that toggles between 3 different

Looking to create a button with 3 different states that handle click events and send values.

The states needed are:

  • Non-favourite
  • Favourite
  • Uber-favourite

Attempted using this.state.count + 1 to represent the levels but faced challenges. Unsure if this is the best approach.

Utilizing const fill for CSS color value passed into the svg element.

Current implementation falls short as checked only has 2 states (on/off) instead of the required 3. Example code available on this codepen.

class Switch extends React.Component {
  constructor ( props ) {
    super( props );
    this.state = {
      checked: !!props.checked
    };
  }
  handleClick(e) {
        this.setState({
      checked: !this.state.checked
    });
  }

  render () {
    const fill = this.state.checked ? "#E1E0DD" : "#999999";
    return (
        <button className="switch" onClick={this.handleClick.bind(this)} >
      <svg width="100" height="100">
        <g>
          <path id="svg_2" d="m0,38l37,0l11,-38l11,38l37,0l-30,23l11,38l-30,-23l-30,23l11,-38l-30,-23l0,0z" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="0" fill={fill} />
        </g>
      </svg>
            </button>
    );
  }
}

const App = () => (
    <div>
        <Switch checked={ true } />
    </div>
)

React.render( <App />, document.getElementById( "page" ) );

Answer №1

Your code has multiple issues that need to be addressed.

First and foremost, avoid deriving a component's state from its props as it is considered an anti-pattern.

Additionally, when you base new state on previous state in React, make sure to use the function(prevState, nextProps) argument instead of an object with setState due to possible batching of setState calls.

Lastly, using a boolean to achieve three states, as indicated in the comment above, is not a viable approach.

A more appropriate implementation would look something like this:

class TripleSwitch extends React.Component {
  constructor() {
    super();
    this.state = {
       favourite: 0
    }
  }

  handleClick() {
    this.setState((prevState) => ({
       favourite: (prevState.favourite + 1) % 3
    }));
  }

  render () {
    const { favourite } = this.state;
    const fill = favourite === 0 ? "#E1E0DD" :
                 favourite === 1 ? "#000444" : 
                 "#999999";
    return (
        <button className="switch" onClick={this.handleClick.bind(this)} >
      <svg width="100" height="100">
        <g>
          <path id="svg_2" d="m0,38l37,0l11,-38l11,38l37,0l-30,23l11,38l-30,-23l-30,23l11,-38l-30,-23l0,0z" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="0" fill={fill} />
        </g>
      </svg>
            </button>
    );
  }
}

Answer №2

I made a copy of the codepen you shared

In the realm of boolean values, it's either 1 or 0. To have more states, you'll need to increment a value accordingly.

  handleClick(e) {
    var count = this.state.count;
    count = count !== 3 ? count + 1 : 0;
    this.setState({
      count: count
    });
  }

It's also a good idea to keep your logic for fill color separate:

function fillColor(count) {
    var fill = "";
    if(count === 1) fill = "#E1E0DD";
    if(count === 2) fill = "#999999";
    if(count === 3) fill = "#000";
    return fill;
}

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

Building a customized Mui clip with child support: A step-by-step guide

Looking to create a customized chip that can handle both single and nested declarations? Check out this example using MUI v5. interface StyledModalChipProps { theme: Theme children: React.ReactNode } export const StyledModalChip = styled(Chip)<Styled ...

Deselect all event listeners excluding the ones specified in Socket.io

I have a node.js application using socket.io to dynamically load external modules, referred to as "activities," in real-time. Each module binds its own events to the sockets, so when switching from one module to another, I need to remove all event listene ...

Navigating through a document: Loading or 404 error in Meteor and React

Here is a code snippet that I am working with: import React, { Component } from 'react'; import { withTracker } from 'react-meteor-data'; import Auctions from '../collections/Auctions'; class AuctionPage extends Component { ...

Is there a way to send arguments to a pre-existing Vue JS application?

A Vue application we've developed connects to a Web Service to retrieve data. However, the URL of the web service varies depending on the installation location of the app. Initially, we considered using .env files for configuration, but realized that ...

Nextjs Suspense does not support the fetch API, but it works perfectly with new Promise timeouts

I am facing an issue with Next.js where I cannot display suspense fallback when trying to fetch data using the Fetch API. However, if I use a new promise with setTimeout, it works perfectly. Since the Fetch API is based on promises, why does suspense fail ...

Is there a different method like Calc() to create a static sidebar alongside content?

Is there a way to achieve a fixed sidebar on the left and a content area on the right without using calc() in CSS? I'm looking for a more universally supported method that works across different browsers. .left-sidebar { width: 160px; ...

Adjust time according to specified time zone using JavaScript

I am working on a project involving clocks and timezones. The user should be able to choose a timezone from a combobox, and upon selection, the main digital clock should update to display the time for that timezone. I have a text file called 'zone.txt ...

Struggling with a findIndex problem in React and JavaScript

Whenever I receive activeFilters values like this: const filter = [...activeFilters] The findIndex function always returns -1 even when the item I'm searching for exists. However, when I receive it like this, it works? const filter = activeFilters ...

Unable to retrieve data on the frontend using Node.js and React

I have been attempting to retrieve all user data from the backend to display on the webpage. However, it seems that the getAllUsers() function is not returning a response, as no console logs are being displayed. Here is my ViewUsers.js file: import React, ...

Implement an AJAX function to prompt a save dialog before initiating the download process

I'm currently programming an embedded device in C with a web server. One of the tasks I am working on is downloading files from this device. I need to download several files at once, so I've set up an AJAX request that uses a POST method and send ...

The promise is throwing an error stating that it cannot read the property 'code' of undefined when using the context api in React hooks

I'm currently working on developing my first hybrid web app using React Hooks. I've encountered a timing issue involving promises and the Context API. Here's the challenge I'm dealing with. A function called fetchApplications retrieve ...

Designing a Curved Stepper Component in the Shape of an S

I've been attempting to create a custom stepper component with an S-curve shape using React, but so far I haven't been successful. I even tried utilizing the MUI Stepper component and experimented with pure HTML and CSS, but couldn't achieve ...

What is the best way to add a CSS rule to JavaScript?

animation: scaleUp 0.3s linear 0.4s forwards; animation: scaleDown 0.3s linear forwards; Greetings! I'm currently working on adding animations to my content filtering functionality. Specifically, I want to incorporate the aforementioned CSS rules in ...

Display images that have been uploaded on the page either as a grid view or a list of

In my Reactjs application, I am uploading multiple images to Azure Blob Storage. On a page, there is a button to open the upload form. Once the upload completes, I want to display all these images on the same page. Since the images have different aspect ...

Is the hardware acceleration of the iPhone 4 significantly weaker than that of the iPhone 4s?

My HTML5 web application utilizes hardware acceleration through the CSS3 property translateZ(0). Everything runs smoothly on my 4s device. However, when I try the same application on an iPhone4, the performance drastically decreases and becomes almost un ...

SASS: incorporating loops within CSS properties

Is there a way to generate multiple values for a single property in CSS? background-image: radial-gradient(circle, $primary 10%, transparent 10%), radial-gradient(circle, $primary 10%, transparent 10%), radial-gradient(circle, $primary 10%, tr ...

Mastering the art of throwing and managing custom errors from the server to the client side within Next.js

I'm in the process of developing a Next.js application and I am faced with the challenge of transmitting customized error messages from the server to the client side while utilizing Next JS new server-side actions. Although my server-side code is func ...

Is there a discrepancy in performance when running a function on an individual element versus a group of elements within jQuery?

Imagine having the choice between applying a function to an individual DOM element or a list of them: For Individual Elements: $('#element1').click(function () { $(this).hide(); return false; }); $('#element2').click(functi ...

When using Node.js, Express.js, and MongoDB, ensure that the route.post() function is provided with proper callback functions instead of

I've been working on setting up a MEAN (MongoDB, Express, Node.js, Angular 6) application. I'm trying to post user signup form data to a MongoDB database, but I keep getting an error message. This is my first time working with the MEAN stack and ...

I noticed that my API call is being executed twice within the router function

In my NextJs project, I am utilizing Express for routing. I have implemented a router with a dynamic :id parameter which triggers an axios call to check the ID in the database. However, I am facing an issue where the API is being called twice when the :id ...