Material-ui的开关组件onChange处理程序未触发。

10

我在一个应用程序中放置了一些Switch,它们工作得很好。然后我将这些Switch放入另一个应用程序中,但当点击时它们不起作用。

这两个应用程序都使用相同的组件。以下是在一个应用程序中的效果:

enter image description here

这里是另一个应用程序,但是它没有起作用:

enter image description here

在第二个应用程序中,onChange处理程序似乎永远不会触发。

这两个应用程序中的代码看起来像下面这样:

<Switch
  checked={(console.log('checked:', status === 'visible'), status === 'visible')}
  onChange={(e, c) => console.log('event:', e, c)}
/>

在第一个应用程序中,我看到了这些console.log的输出,而在第二个应用程序中,我只看到了checked prop的初始console.log,但我从未看到任何onChange prop。
我检查了是否有任何祖先元素具有click处理程序,但我没有找到任何返回false,调用stopPropagation或调用preventDefault的处理程序。
请注意,在gif中,当我单击时,涟漪效果仍然有效,因此单击处理显然仍在工作。
任何想法为什么onChange可能不会触发?
更新!我用普通的<input type="checkbox">元素替换了开关,它运行得很好!请参见: enter image description here 对我来说,material-ui的<Switch>组件出了问题。我有一种直觉,我会在有机会时进行调查:应用程序中可能会有多个React单例。我会回来发布更新。

Switch 父组件上有任何点击事件处理程序吗? - Hai Pham
在初始化时,是否触发了 console.log('event:', e, c) - Hai Pham
@HaiPham 它从未触发过。 - trusktr
@RyanCogswell 上面的例子就是全部内容。我将开关放在第二个应用程序中,除了您看到的内容之外,没有做任何特殊处理,然后当我单击开关时,“onChange”从未触发。我有一个想法:也许我在应用程序中有多个React版本。我要测试一下这个。 - trusktr
@RyanCogswell 显然周围有一些渲染的东西,我把它放在其他元素里面。但是我仔细检查了一下,没有任何click事件阻止传播或防止默认行为。事实上,我用普通的<input type="checkbox">元素替换了Switches,效果很好。material-ui的Switch出了点问题。 - trusktr
显示剩余12条评论
8个回答

6

我认为这个修复方法有点奇怪,但是它对我来说运行得很顺畅。因此,我正在使用handleClick而不是handleChange。我在这里不使用事件,而是传递一个字符串,这显然是状态的名称或数组中的id。

<Switch
    checked={this.state.active}
    onClick={() => this.handleToggle('active')}
    value="active"
    inputProps={{ 'aria-label': 'secondary checkbox' }}
/>

handleToggle = (name: string) => {
    this.setState({ active: !this.state.active });
};

我尝试过使用handleChange,但问题仍然存在。希望这个问题能够很快得到解决。


2

我曾在WordPress管理区域遇到CheckboxSwitch相同的问题。

结果发现,存在一个全局CSS规则:

input[type="checkbox"] {
  height: 1rem;
  width: 1rem;
}

点击元素左上角也可以。不过,我的解决方案是在应用的根部重置了一些样式。
编辑:算了,我把整个应用程序放到了 Shadow DOM 中。这里有几个需要注意的地方:
  1. 必须为 Shadow DOM 中的 Material UI 样式元素提供自定义插入点。通常情况下,不能让任何东西放在你的 Shadow DOM 之外。
  2. 必须在 Shadow DOM 和 Light DOM 中都加载或链接字体。
  3. 使用 ScopedCssBaseline 来代替全局重置。
  4. 对话框必须指定它们的 container 属性。
以下是我如何使用 Material-UI 设置的内容:
// configure-shadow-dom.js

import { create } from 'jss';
import { jssPreset } from '@material-ui/core/styles';

const shadowHostId = 'my-app-root-id'

export const appRoot = document.createElement('div')
appRoot.setAttribute('id', 'app-root')

const styleInsertionPoint = document.createComment('jss-insertion-point')
export const jss = create({
    ...jssPreset(),
    insertionPoint: styleInsertionPoint,
})

const robotoFontLink = document.createElement('link')
robotoFontLink.setAttribute('rel', 'stylesheet')
robotoFontLink.setAttribute('href', 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap')

const shadowHost = document.getElementById(shadowHostId)
shadowHost.attachShadow({ mode: 'open' })

const shadowRoot = shadowHost.shadowRoot
shadowRoot.appendChild(robotoFontLink)
shadowRoot.appendChild(styleInsertionPoint)
shadowRoot.appendChild(appRoot)


// index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import ScopedCssBaseline from '@material-ui/core/ScopedCssBaseline';
import { StylesProvider } from '@material-ui/core/styles';
import App from './App';
import { jss, appRoot } from './configure-shadow-dom';

ReactDOM.render(
    <React.StrictMode>
        <StylesProvider jss={jss}>
            <ScopedCssBaseline>
                <App />
            </ScopedCssBaseline>
        </StylesProvider>
    </React.StrictMode>,
    appRoot
);

1

我仍然遇到了从交换机获取事件的类似问题。这里有一个使用内部状态的快速修复方法(如果您还没有使用钩子和函数组件,则应该使用,否则您会错过一些好处,但您可以在类组件中使用 setState 来执行我在这里展示的操作)。

const [switchChecked, setSwitchChecked] = useState(false);

.......

<Switch checked={switchChecked} onChange={() => {setSwitchChecked(!switchChecked);}}/>

你需要在组件的本地状态中有一个switchChecked的值。

1
事实证明,在我的情况下,页面中有一个类似于CSS的东西。
.some-component { pointer-events: none; }
.some-component * { pointer-events: auto; }

在我的代码中,.some-component 包含了我的 material-ui 按钮和开关。我不得不手动设置 pointer-eventsall(或者其他值,我现在记不清了)以使开关内部的元素可以正常使用。

因此,需要注意的一点是:检查 pointer-events 样式的作用。


1
在Switch组件中,将onChange更改为onClick对我有效:
<Switch
    checked={this.state.active}
    onClick={() => this.handleToggle('active')}
    value="active"
    inputProps={{ 'aria-label': 'secondary checkbox' }}
/>

0
问题在于您必须从事件中嗅探checked属性:event.target.checked

完整解决方案:

import { Switch } from '@material-ui/core';
import { useState } from 'react';

function App() {
  const [checked, setChecked] = useState(false);

  const switchHandler = (event) => {
    //THIS IS THE SOLUTION - use event.target.checked to get value of switch
    setChecked(event.target.checked);
  };

  return (
    <div>
      <Switch checked={checked} onChange={switchHandler} />
    </div>
  );
}

export default App;

1
这似乎会破坏开关的默认动画 - 你知道为什么吗? - Cookster
这对我也不起作用。唯一让它对我起作用的是使用点击事件,然后我只需切换自己的布尔状态变量。即使如此,它仍然存在缺陷,并且似乎随机地无法正确触发默认动画。这个组件有很多漏洞。 - Kyle Zimmer

0
经过浪费了一个小时的时间,我才知道 switch 在 e.target.checked 中提供了一个值,这个值会在单击时切换(true/false)。
 const [taxIncluded, setTaxIncluded] =useState(false)
       const taxIncludeChange = (e) => {
    console.log(e.target.checked, 'checked value here (true/false)');
  };
<Switch onChange={taxIncludeChange} value={taxIncluded} color="primary" />

0

尝试将其作为第二个参数传递,选中或取消选中其中一个。

<Switch
    checked={this.state.active}
    onClick={(e,flag) => this.handleToggle('active', flag)}
    value="active"
    inputProps={{ 'aria-label': 'secondary checkbox' }}
/>```

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接