markusenglund / react-switch

A draggable toggle-switch component for React. Check out the demo at:
https://react-switch.netlify.com/
MIT License
1.33k stars 100 forks source link

Switch is only draggable, not toggled by click #75

Open KidA001 opened 4 years ago

KidA001 commented 4 years ago

I'm on React 16.12.0 and react-switch 5.0.1

When I render react-switch it is only draggable, but does not change/toggle when I click it. I found this issue however that seemed related to an iFrame which I'm not using.

I put a console.log(checked) in the handleChange function and it always outputs false regardless of what the state of the switch is.

Below is the component I'm loading the switch in. My only guess is it might have something to do with the async methods or with me setting the state in the View() function, but it's not clear to me what I'm doing wrong.

import React, { Component } from "react"
import axios from 'axios';
import Switch from "react-switch";

import HidingContainer from "../HidingContainer"
import NumericValue from "../NumericValue/index"

class HotTub extends Component {
  constructor() {
    super();
    this.state = { checked: false };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(checked) {
    this.setState({ checked });
  }

  async componentDidMount() {
    await this.View();
  }

  CustomSwitch = () => {
    return (
      <Switch
        onChange={this.handleChange}
        checked={this.state.checked}
        onColor="#86d3ff"
        onHandleColor="#2693e6"
        handleDiameter={30}
        uncheckedIcon={false}
        checkedIcon={false}
        boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)"
        activeBoxShadow="0px 0px 1px 10px rgba(0, 0, 0, 0.2)"
        height={20}
        width={48}
        className="react-switch"
        id="material-switch"
      />
    )
  }

  async getHotTubStatus() {
    const response = await axios({
      url: "http://localhost:3000/hot-tub-status",
      method: 'get'
    });

    return response.data
  }

  async View() {
    const hotTubStatus = await this.getHotTubStatus()

    this.setState({
      checked: hotTubStatus.on, // sets initial state
      View: (
        <NumericValue value={hotTubStatus.temperature} unit="°F" />
        <this.CustomSwitch />
      )
    })
  }

  render() {
    return (
      <HidingContainer metricsRef={React.createRef()}>
        {this.state.View}
      </HidingContainer>
    )
  }
}

export default HotTub

Any insight/help appreciated

MrWillian commented 4 years ago

UP! I have the same problem.

adarshaacharya commented 4 years ago

can you tell me how to make the circle part offcolor when i'm not clicking or focusing it !

amosyu2000 commented 4 years ago

Bump. I'm having the same issue

benomatis commented 4 years ago

@KidA001 I might not be correct with this, but could it be because every time you try to change the checked state, you call a setState which will cause the component to be re-rendered, which will then cause componentDidMount to trigger every time, so you're fetching the same checked state again from the server, so basically the switch always sets back to the same value.

Try to find a way to call View() only once when the component is loaded first either by getting the contents of View() from the parent component, setting a falsy local variable to true after the first mount and check for it the 2nd time, or if you are using hooks, provide an empty array as the second argument of useEffect().

markusenglund commented 3 years ago

Hi, sorry for the late response.

@KidA001 Rendering the CustomSwitch component in the state of the parent, and at the same time trying to read state from the parent inside the CustomSwitch is definitely going to lead to unexpected behavior. Here's a sandbox which should work better: https://codesandbox.io/s/dark-snowflake-mms03?file=/src/index.js

To everyone else in the thread: Could you fork this Code sandbox and create a minimal reproduction of the issue you're facing?

EDIT: Here's a version that still works: https://codesandbox.io/s/jolly-ishizaka-k574z?file=/src/index.js

iamAbdulAhad3481 commented 3 years ago

Hey still facing the same issue <SwitchCheckBox onChange={handleChange} checked={checked} uncheckedIcon={false} checkedIcon={false} onColor="#86d3ff" onHandleColor="#2693e6" handleDiameter={30} boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)" activeBoxShadow="0px 0px 1px 10px rgba(0, 0, 0, 0.2)" height={20} width={48} className="react-switch" id="material-switch" />

const handleCheckBox = (checked) => { setFormData({ ...formData, isMonitoringStock: checked }) } Can please anyone tell me what,s the issue

BSiddharth commented 3 years ago

One way around this problem is to pass an empty callback function to the Switch and then wrap that Switch with a div element. Then pass onTap/onClick callback function to this div element. It will also allow you to drag and toggle if you don't drag the cursor out of the Switch UI model. (I did not find any way around this, frankly it doesn't bother me so I did not try to find any)

benomatis commented 3 years ago

@iamAbdulAhad3481

Hey still facing the same issue <SwitchCheckBox onChange={handleChange} checked={checked} uncheckedIcon={false} checkedIcon={false} onColor="#86d3ff" onHandleColor="#2693e6" handleDiameter={30} boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)" activeBoxShadow="0px 0px 1px 10px rgba(0, 0, 0, 0.2)" height={20} width={48} className="react-switch" id="material-switch" />

const handleCheckBox = (checked) => { setFormData({ ...formData, isMonitoringStock: checked }) } Can please anyone tell me what,s the issue

This largely depends on how the checked state looks like in your app, what triggers its change, and lifecycle hooks you have that influence it... etc; the code you pasted unfortunately doesn't have this info.

As a general rule of thumb, this appears to be an issue with the incorrect handling of the checked state, ie. it's either not changing on click, or it's immediately changing again or changing indefinitely in the background back and forth.

What I do in cases like this to troubleshoot is I create a small line that's printing out the value of a state, something around the lines of <div>{ checked ? 'checked' : 'not' }</div>.

markusenglund commented 3 years ago

@BSiddharth Could you provide a reproduction of the issue in code sandbox and explain the issue as well as what platform & browser are affected?

BSiddharth commented 3 years ago

@markusenglund Interestingly the simple code I wrote in the sandbox works. I will check my full code and will update it here later when I get time.

Edit - Well it works now for some reason. I just uncommented the old code and commented the new one. And its working okay. Maybe because I updated to the latest Firefox 93.0 since last I ran that code??

derwaldgeist commented 2 years ago

I have the same problem on macOS now, with the recent Chrome version 96.0. It worked before. But now, I can enable a switch, but not disable it. And even worse: if you try to switch multiple switches on a page, all of the sudden all switches move. This does not happen on iOS or Firefox. On Android, it kinda works, but sometimes the animations are missing.

markusenglund commented 2 years ago

Can anyone confirm derwaldgeist problem? As I wrote in his issue I don't have access to a MacOS device. I briefly tested the demo page on chrome 96 on macos via browserstack and couldn't reproduce the issue on the demo page.

derwaldgeist commented 2 years ago

Hi @markusenglund: Closing this. It seems as if this was a temporary hick-up of Chrome which vanished after I restarted my Mac. Sorry for the confusion.