Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/packages/switch/demos/h5/demo2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@ import { Cell, Switch, Toast } from '@nutui/nutui-react'
const Demo2 = () => {
const [checkedAsync, setCheckedAsync] = useState(true)

const onChangeAsync = (value: boolean, event: any) => {
const mockRequest = (): Promise<void> => {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, 2000)
})
}

const onChangeAsync = async (value: boolean) => {
Toast.show(`2秒后异步触发 ${value}`)
setTimeout(() => {
setCheckedAsync(value)
}, 2000)
await mockRequest()
setCheckedAsync(value)
}
return (
<Cell>
<Switch
checked={checkedAsync}
onChange={(value, event) => onChangeAsync(value, event)}
onChange={(value) => onChangeAsync(value)}
/>
</Cell>
)
Expand Down
4 changes: 2 additions & 2 deletions src/packages/switch/demos/taro/demo2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const Demo2 = () => {
const [value, setValue] = useState(false)
const [showToast, setShowToast] = useState(false)

const onChangeAsync = (value: boolean, event: any) => {
const onChangeAsync = (value: boolean) => {
setValue(value)
setShowToast(true)
setTimeout(() => {
Expand All @@ -18,7 +18,7 @@ const Demo2 = () => {
<Cell>
<Switch
checked={checkedAsync}
onChange={(value, event) => onChangeAsync(value, event)}
onChange={(value) => onChangeAsync(value)}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

更新事件处理器,匹配新的函数签名

更新了onChange属性的回调函数,现在只传递value参数给onChangeAsync函数,符合新的函数签名。

在异步操作期间(2秒延迟),应添加加载状态指示器以提升用户体验。建议在Switch组件中添加一个loading属性,并在状态更新前将其设置为true:

+  const [loading, setLoading] = useState(false)

  const onChangeAsync = (value: boolean) => {
    setValue(value)
    setShowToast(true)
+   setLoading(true)
    setTimeout(() => {
      setCheckedAsync(value)
+     setLoading(false)
    }, 2000)
  }

  return (
    <>
      <Cell>
        <Switch
          checked={checkedAsync}
+         loading={loading}
          onChange={(value) => onChangeAsync(value)}
        />
      </Cell>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onChange={(value) => onChangeAsync(value)}
import React, { useState } from 'react';
const Demo2 = () => {
const [value, setValue] = useState(false);
const [checkedAsync, setCheckedAsync] = useState(false);
const [showToast, setShowToast] = useState(false);
const [loading, setLoading] = useState(false);
const onChangeAsync = (value: boolean) => {
setValue(value);
setShowToast(true);
setLoading(true);
setTimeout(() => {
setCheckedAsync(value);
setLoading(false);
}, 2000);
};
return (
<>
<Cell>
<Switch
checked={checkedAsync}
loading={loading}
onChange={(value) => onChangeAsync(value)}
/>
</Cell>
</>
);
};
export default Demo2;

/>
</Cell>
<Toast
Expand Down
10 changes: 2 additions & 8 deletions src/packages/switch/demos/taro/demo6.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,14 @@ import { Cell, Switch, Toast } from '@nutui/nutui-react-taro'
const Demo6 = () => {
const [value, setValue] = useState(false)
const [showToast, setShowToast] = useState(false)
const onChange = (
value: boolean,
event: React.MouseEvent<Element, MouseEvent>
) => {
const onChange = (value: boolean) => {
setValue(value)
setShowToast(true)
}
return (
<>
<Cell>
<Switch
defaultChecked
onChange={(value, event) => onChange(value, event)}
/>
<Switch defaultChecked onChange={(value) => onChange(value)} />
</Cell>
<Toast
content={`触发了onChange事件,开关状态:${value}`}
Expand Down
5 changes: 5 additions & 0 deletions src/packages/switch/switch.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
left: calc(100% - $switch-height + $switch-border-width);
}
}
.nut-icon {
width: calc(($switch-height - $switch-border-width * 2) / 2);
height: calc(($switch-height - $switch-border-width * 2) / 2);
color: $switch-active-disabled-background-color;
}
}

&-close {
Expand Down
39 changes: 24 additions & 15 deletions src/packages/switch/switch.taro.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { FunctionComponent } from 'react'
import React, { FunctionComponent, useEffect, useState } from 'react'

import { ITouchEvent, View } from '@tarojs/components'
import { View } from '@tarojs/components'
import classNames from 'classnames'
import { Loading1 } from '@nutui/icons-react-taro'
import { ComponentDefaults } from '@/utils/typings'
import { usePropsValue } from '@/hooks/use-props-value'
import { useRtl } from '@/packages/configprovider/index.taro'
Expand Down Expand Up @@ -37,6 +38,12 @@ export const Switch: FunctionComponent<Partial<TaroSwitchProps>> = (props) => {
defaultValue: defaultChecked,
})

useEffect(() => {
changing && setChanging(false)
}, [value])

const [changing, setChanging] = useState(false)

const classes = () => {
return classNames([
classPrefix,
Expand All @@ -49,20 +56,16 @@ export const Switch: FunctionComponent<Partial<TaroSwitchProps>> = (props) => {
])
}

const onClick = (
event: React.MouseEvent<Element, MouseEvent> | ITouchEvent
) => {
if (disabled) return
onChange && onChange(!value, event)
const onClick = () => {
if (disabled || changing) return
if (props.onChange) {
setChanging(true)
props.onChange(!value)
}
setValue(!value)
}
return (
<View
className={classes()}
onClick={(e) => onClick(e)}
style={style}
{...rest}
>
<View className={classes()} onClick={onClick} style={style} {...rest}>
<View
className={classNames([
[`${classPrefix}-button`],
Expand All @@ -77,8 +80,14 @@ export const Switch: FunctionComponent<Partial<TaroSwitchProps>> = (props) => {
},
])}
>
{!value && !activeText && (
<View className={`${classPrefix}-close-line`} />
{changing ? (
<Loading1 />
) : (
<>
{!value && !activeText && (
<View className={`${classPrefix}-close-line`} />
)}
</>
)}
</View>
{activeText && (
Expand Down
35 changes: 23 additions & 12 deletions src/packages/switch/switch.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FunctionComponent } from 'react'
import React, { FunctionComponent, useEffect, useState } from 'react'
import classNames from 'classnames'
import { Loading1 } from '@nutui/icons-react'
import { ComponentDefaults } from '@/utils/typings'
import { usePropsValue } from '@/hooks/use-props-value'
import { useRtl } from '@/packages/configprovider'
Expand Down Expand Up @@ -35,6 +36,12 @@
defaultValue: defaultChecked,
})

useEffect(() => {
changing && setChanging(false)
}, [value])

const [changing, setChanging] = useState(false)
Comment on lines +41 to +45
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

添加状态重置逻辑和状态变量

这段代码添加了两个关键功能:

  1. 使用 useEffectvalue 变化时重置 changing 状态
  2. 引入 changing 状态来跟踪组件的异步变化过程

这是处理异步状态变化的良好实践,但需确保测试覆盖。


🏁 Script executed:

#!/bin/bash
# 检查是否存在测试文件并验证是否覆盖了新增的状态逻辑
echo "查找 Switch 组件的测试文件..."
fd "switch.*test" --type f

Length of output: 79


代码状态变化逻辑已正确引入,但缺少相应测试覆盖

当前修改在 src/packages/switch/switch.tsx 中完成了以下两项关键变更:

  • 使用 useEffect 监听 value 的变化,并在变化时自动将 changing 状态重置为 false
  • 新增 changing 状态变量来追踪组件异步变化过程。

这些改动整体逻辑清晰且符合异步状态处理的良好实践。不过,通过执行检测脚本,目前没有找到针对 Switch 组件新增逻辑的测试文件。请确认或新增相应的单元测试,确保覆盖以下方面:

  • value 变化时,changing 状态能正确重置;
  • 异步状态变化过程中的其它相关交互行为。


const classes = () => {
return classNames([
classPrefix,
Expand All @@ -47,18 +54,16 @@
])
}

const onClick = (event: React.MouseEvent<Element, MouseEvent>) => {
if (disabled) return
onChange && onChange(!value, event)
const onClick = () => {
if (disabled || changing) return
if (props.onChange) {
setChanging(true)
props.onChange(!value)
}

Check warning on line 62 in src/packages/switch/switch.tsx

View check run for this annotation

Codecov / codecov/patch

src/packages/switch/switch.tsx#L58-L62

Added lines #L58 - L62 were not covered by tests
setValue(!value)
}
Comment on lines +60 to 66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

需要添加测试覆盖新增功能

静态分析工具显示这些关键的新增代码行没有测试覆盖,特别是:

  1. 异步加载状态的处理逻辑
  2. 加载图标的渲染

建议增加测试用例确保这些功能在各种条件下正常工作,例如:

  • 测试点击后的 changing 状态变化
  • 测试 value 更新后 changing 状态的重置
  • 测试加载图标的正确渲染
  • 测试在 changing 状态下点击不触发 onChange

这些测试对确保组件的稳定性和可靠性非常重要。

Also applies to: 84-84


🏁 Script executed:

#!/bin/bash
# 查找与 Switch 组件相关的测试文件和测试覆盖情况
echo "检查 Switch 组件的测试文件..."
fd "switch.*test" --type f

echo "检查测试中是否已经测试了异步处理逻辑..."
if fd "switch.*test" --type f | xargs rg -l "changing|loading|async"; then
  echo "找到了可能包含异步处理逻辑测试的文件"
else
  echo "未找到包含异步处理逻辑测试的文件"
fi

Length of output: 13008


请完善测试覆盖异步状态和加载图标功能

目前静态分析工具提示,新增的代码逻辑缺少相应的测试验证,建议对以下情况补充测试用例:

  • 点击事件后 changing 状态的变化:验证点击后是否正确设置 changing 状态,以及在 value 更新后该状态是否能重置。
  • 加载图标的渲染:确保在异步加载状态下加载图标能够正确显示。
  • changing 状态下的点击行为:测试当组件处于变化中(changingtrue)时,点击是否会被正确忽略,以防止重复触发 props.onChange

此外,这些问题同样适用于文件中其它局部相似的代码(例如:行 84)。请参考现有的 Switch 组件测试文件(如 src/packages/switch/__test__/switch.spec.tsx)补充对应的测试用例,以提高组件的稳定性和可靠性。

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 60-64: src/packages/switch/switch.tsx#L60-L64
Added lines #L60 - L64 were not covered by tests

return (
<div
className={classes()}
onClick={(e) => onClick(e)}
style={style}
{...rest}
>
<div className={classes()} onClick={onClick} style={style} {...rest}>
<div
className={classNames([
[`${classPrefix}-button`],
Expand All @@ -73,8 +78,14 @@
},
])}
>
{!value && !activeText && (
<div className={`${classPrefix}-close-line`} />
{changing ? (
<Loading1 />

Check warning on line 82 in src/packages/switch/switch.tsx

View check run for this annotation

Codecov / codecov/patch

src/packages/switch/switch.tsx#L82

Added line #L82 was not covered by tests
) : (
<>
{!value && !activeText && (
<div className={`${classPrefix}-close-line`} />
)}
</>
)}
</div>
{activeText && (
Expand Down
4 changes: 2 additions & 2 deletions src/types/spec/switch/base.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ReactNode } from 'react'
import { BaseProps } from '../../base/props'

export interface BaseSwitch<EVENT = any> extends BaseProps {
export interface BaseSwitch extends BaseProps {
checked: boolean
defaultChecked: boolean
disabled: boolean
activeText: ReactNode
inactiveText: ReactNode
onChange: (val: boolean, event: EVENT) => void
onChange: (val: boolean) => void
}
2 changes: 1 addition & 1 deletion src/types/spec/switch/h5.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { BaseSwitch } from '../switch/base'

export interface WebSwitchProps extends BaseSwitch<React.MouseEvent> {}
export interface WebSwitchProps extends BaseSwitch {}
4 changes: 1 addition & 3 deletions src/types/spec/switch/taro.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ITouchEvent } from '@tarojs/components'
import { BaseSwitch } from './base'

type UnionEvent = React.MouseEvent<Element, MouseEvent> | ITouchEvent
export interface TaroSwitchProps extends BaseSwitch<UnionEvent> {}
export interface TaroSwitchProps extends BaseSwitch {}
Loading