Skip to content

Commit

Permalink
fix(Address): 修复Address组件通过点击CloseIcon和Overlay关闭后,无法再次打开的问题 (#1233)
Browse files Browse the repository at this point in the history
  • Loading branch information
TralafalgarV authored Jul 20, 2023
1 parent bc1ca47 commit 7aa2283
Show file tree
Hide file tree
Showing 9 changed files with 499 additions and 75 deletions.
59 changes: 57 additions & 2 deletions src/packages/address/__test__/address.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import { fireEvent, render } from '@testing-library/react'
import React, { useRef } from 'react'
import { fireEvent, render, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom'
import { Address } from '../address'

Expand Down Expand Up @@ -179,3 +179,58 @@ test('Address: exist defaultIcon & selectIcon', async () => {
fireEvent.click(items[1])
expect(items[1].innerHTML).toContain('<div class="select">456</div>')
})

function sleep(delay = 0): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, delay)
})
}

describe('Address', () => {
interface WrapperProps {
visible: boolean
}

const Wrapper: React.FC<WrapperProps> = ({ visible }) => {
const ref = useRef<any>()
return (
<div>
<button onClick={() => ref.current?.open()}>Open</button>
<button onClick={() => ref.current?.close()}>Close</button>
<Address
defaultVisible={visible}
ref={ref}
options={optionsDemo1}
title="选择地址"
/>
</div>
)
}

it('should handle open and close methods', async () => {
const screen = render(<Wrapper visible={false} />)

fireEvent.click(screen.getByText('Open'))
await waitFor(
async () => {
await sleep(1000)
const title = screen.container.querySelector('.nut-popup-title')
expect(title?.innerHTML).toBe('选择地址')
},
{
timeout: 2000,
}
)

fireEvent.click(screen.getByText('Close'))
await waitFor(
async () => {
await sleep(1000)
expect(screen.container.querySelector('.nut-popup-title')).toBe(null)
},
{
timeout: 2000,
}
)
})
})
58 changes: 43 additions & 15 deletions src/packages/address/address.taro.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import React, { FunctionComponent, useEffect, useState } from 'react'
import React, {
ForwardRefRenderFunction,
useImperativeHandle,
forwardRef,
useState,
} from 'react'
import { Left } from '@nutui/icons-react-taro'
import Popup from '@/packages/popup/index.taro'
import { ExistRender } from './existRender.taro'
Expand All @@ -12,9 +17,16 @@ import {
CascaderValue,
} from '@/packages/cascader/index.taro'
import { ComponentDefaults } from '@/utils/typings'
import { usePropsValue } from '@/utils/use-props-value'

type AddressRef = {
open: () => void
close: () => void
}

export interface AddressProps extends CascaderProps {
visible: boolean
defaultVisible: boolean
value?: CascaderValue
defaultValue?: CascaderValue
type: string
Expand All @@ -34,7 +46,6 @@ export interface AddressProps extends CascaderProps {

const defaultProps = {
...ComponentDefaults,
visible: false,
defaultValue: [],
type: 'custom',
options: [],
Expand All @@ -49,18 +60,20 @@ const defaultProps = {
backIcon: null,
} as unknown as AddressProps

export const Address: FunctionComponent<
const InternalAddress: ForwardRefRenderFunction<
AddressRef,
Partial<AddressProps> &
Omit<
React.HTMLAttributes<HTMLDivElement>,
'onChange' | 'defaultValue' | 'onLoad' | 'title' | 'onClick'
>
> = (props) => {
> = (props, ref) => {
const { locale } = useConfig()
const {
style,
className,
visible,
defaultVisible,
defaultValue,
children,
type,
Expand All @@ -79,7 +92,6 @@ export const Address: FunctionComponent<
onExistSelect,
onClose,
onSwitch,

...rest
} = {
...defaultProps,
Expand All @@ -88,14 +100,27 @@ export const Address: FunctionComponent<

const classPrefix = 'nut-address'
const [currentType, setCurrentType] = useState<string>(type)
const [showPopup, setShowPopup] = useState(visible)
const [innerVisible, setInnerVisible] = usePropsValue<boolean>({
value: visible,
defaultValue: defaultVisible,
finalValue: defaultVisible,
})

const handClose = () => {
setShowPopup(false)
useImperativeHandle(ref, () => {
return {
open() {
setInnerVisible(true)
},
close() {
setInnerVisible(false)
},
}
})

const handleClose = () => {
setInnerVisible(false)
onClose && onClose()
}
useEffect(() => {
setShowPopup(visible)
}, [visible])

const renderLeftOnCustomSwitch = () => {
return (
Expand All @@ -115,7 +140,7 @@ export const Address: FunctionComponent<

const selectedExistItem = (data: AddressList) => {
onExistSelect && onExistSelect(data)
handClose()
handleClose()
}

// 切换地址选择模式
Expand All @@ -131,7 +156,7 @@ export const Address: FunctionComponent<
<>
{currentType === 'custom' || currentType === 'custom2' ? (
<CustomRender
visible={showPopup}
visible={innerVisible}
closeable
title={title || locale.address.selectRegion}
left={renderLeftOnCustomSwitch()}
Expand All @@ -141,19 +166,20 @@ export const Address: FunctionComponent<
optionKey={optionKey}
type={currentType}
height={height}
onClose={handClose}
onClose={handleClose}
onChange={(val: CascaderValue, params?: any) => {
onChange?.(val, params)
}}
/>
) : (
<Popup
visible={showPopup}
visible={innerVisible}
position="bottom"
round
closeable
closeIcon={closeIcon}
title={title || locale.address.selectRegion}
onClose={handleClose}
>
<div
className={`${classPrefix} ${className || ''}`}
Expand All @@ -178,5 +204,7 @@ export const Address: FunctionComponent<
)
}

export const Address = forwardRef(InternalAddress)

Address.defaultProps = defaultProps
Address.displayName = 'NutAddress'
57 changes: 43 additions & 14 deletions src/packages/address/address.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import React, { FunctionComponent, useEffect, useState } from 'react'
import React, {
ForwardRefRenderFunction,
useImperativeHandle,
forwardRef,
useState,
} from 'react'
import { Left } from '@nutui/icons-react'
import Popup from '@/packages/popup'
import { CustomRender } from './customRender'
Expand All @@ -12,9 +17,16 @@ import {
CascaderValue,
} from '@/packages/cascader/index'
import { ComponentDefaults } from '@/utils/typings'
import { usePropsValue } from '@/utils/use-props-value'

type AddressRef = {
open: () => void
close: () => void
}

export interface AddressProps extends CascaderProps {
visible: boolean
defaultVisible: boolean
value?: CascaderValue
defaultValue?: CascaderValue
type: string
Expand All @@ -34,7 +46,6 @@ export interface AddressProps extends CascaderProps {

const defaultProps = {
...ComponentDefaults,
visible: false,
defaultValue: [],
type: 'custom',
options: [],
Expand All @@ -49,16 +60,18 @@ const defaultProps = {
backIcon: null,
} as unknown as AddressProps

export const Address: FunctionComponent<
export const InternalAddress: ForwardRefRenderFunction<
AddressRef,
Partial<AddressProps> &
Omit<
React.HTMLAttributes<HTMLDivElement>,
'onChange' | 'defaultValue' | 'onLoad' | 'title'
>
> = (props) => {
> = (props, ref) => {
const { locale } = useConfig()
const {
visible,
defaultVisible,
defaultValue,
children,
type,
Expand Down Expand Up @@ -86,14 +99,27 @@ export const Address: FunctionComponent<
}
const classPrefix = 'nut-address'
const [currentType, setCurrentType] = useState<string>(type)
const [showPopup, setShowPopup] = useState(visible)
const [innerVisible, setInnerVisible] = usePropsValue<boolean>({
value: visible,
defaultValue: defaultVisible,
finalValue: defaultVisible,
})

const handClose = () => {
setShowPopup(false)
useImperativeHandle(ref, () => {
return {
open() {
setInnerVisible(true)
},
close() {
setInnerVisible(false)
},
}
})

const handleClose = () => {
setInnerVisible(false)
onClose && onClose()
}
useEffect(() => {
setShowPopup(visible)
}, [visible])

const renderLeftOnCustomSwitch = () => {
return (
Expand All @@ -113,7 +139,7 @@ export const Address: FunctionComponent<

const selectedExistItem = (data: AddressList) => {
onExistSelect && onExistSelect(data)
handClose()
handleClose()
}

// 切换地址选择模式
Expand All @@ -129,7 +155,7 @@ export const Address: FunctionComponent<
<>
{currentType === 'custom' || currentType === 'custom2' ? (
<CustomRender
visible={showPopup}
visible={innerVisible}
closeable
title={title || locale.address.selectRegion}
left={renderLeftOnCustomSwitch()}
Expand All @@ -139,19 +165,20 @@ export const Address: FunctionComponent<
optionKey={optionKey}
type={currentType}
height={height}
onClose={handClose}
onClose={handleClose}
onChange={(val: CascaderValue, params?: any) => {
onChange?.(val, params)
}}
/>
) : (
<Popup
visible={showPopup}
visible={innerVisible}
position="bottom"
round
closeable
closeIcon={closeIcon}
title={title || locale.address.selectRegion}
onClose={handleClose}
>
<div
className={`${classPrefix} ${className || ''}`}
Expand All @@ -176,5 +203,7 @@ export const Address: FunctionComponent<
)
}

export const Address = forwardRef(InternalAddress)

Address.defaultProps = defaultProps
Address.displayName = 'NutAddress'
Loading

0 comments on commit 7aa2283

Please sign in to comment.