Skip to content

Commit

Permalink
fix: trigger onChange twice when inputting using the input method (#61)
Browse files Browse the repository at this point in the history
* fix: trigger onChange twice when inputting using the input method

* chore: code style
  • Loading branch information
yoyo837 authored Dec 28, 2023
1 parent 9640649 commit 3aba007
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
21 changes: 15 additions & 6 deletions src/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React, {
} from 'react';
import BaseInput from './BaseInput';
import useCount from './hooks/useCount';
import type { InputProps, InputRef } from './interface';
import type { ChangeEventInfo, InputProps, InputRef } from './interface';
import type { InputFocusOptions } from './utils/commonUtils';
import { resolveOnChange, triggerFocus } from './utils/commonUtils';

Expand Down Expand Up @@ -40,7 +40,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
} = props;

const [focused, setFocused] = useState<boolean>(false);
const compositionRef = React.useRef(false);
const compositionRef = useRef(false);

const inputRef = useRef<HTMLInputElement>(null);

Expand All @@ -58,7 +58,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
value === undefined || value === null ? '' : String(value);

// =================== Select Range ===================
const [selection, setSelection] = React.useState<
const [selection, setSelection] = useState<
[start: number, end: number] | null
>(null);

Expand Down Expand Up @@ -97,6 +97,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
| React.ChangeEvent<HTMLInputElement>
| React.CompositionEvent<HTMLInputElement>,
currentValue: string,
info: ChangeEventInfo,
) => {
let cutValue = currentValue;

Expand All @@ -116,6 +117,10 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
inputRef.current?.selectionEnd || 0,
]);
}
} else if (info.source === 'compositionEnd') {
// Avoid triggering twice
// https://github.com/ant-design/ant-design/issues/46587
return;
}
setValue(cutValue);

Expand All @@ -124,21 +129,25 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
}
};

React.useEffect(() => {
useEffect(() => {
if (selection) {
inputRef.current?.setSelectionRange(...selection);
}
}, [selection]);

const onInternalChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
triggerChange(e, e.target.value);
triggerChange(e, e.target.value, {
source: 'change',
});
};

const onInternalCompositionEnd = (
e: React.CompositionEvent<HTMLInputElement>,
) => {
compositionRef.current = false;
triggerChange(e, e.currentTarget.value);
triggerChange(e, e.currentTarget.value, {
source: 'compositionEnd',
});
onCompositionEnd?.(e);
};

Expand Down
4 changes: 4 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,7 @@ export interface InputRef {
select: () => void;
input: HTMLInputElement | null;
}

export interface ChangeEventInfo {
source: 'compositionEnd' | 'change';
}
39 changes: 39 additions & 0 deletions tests/count.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,45 @@ describe('Input.Count', () => {
expect(setSelectionRange).toHaveBeenCalledWith(2, 2);
});

it('input using the input method should trigger onChange once', () => {
const onChange = jest.fn();
const { container } = render(<Input onChange={onChange} />);
const input = container.querySelector('input')!;
fireEvent.compositionStart(input);
fireEvent.compositionUpdate(input, { data: '你' });
fireEvent.compositionEnd(input, { data: '你好' });
fireEvent.input(input, { target: { value: '你好' } });
expect(onChange).toHaveBeenCalledTimes(1);
});

it('using the input method to enter the cropped content should trigger onChange twice', () => {
const onChange = jest.fn();
const onCompositionEnd = jest.fn();
const { container } = render(
<Input
count={{
show: true,
max: 3,
exceedFormatter: (val, { max }) =>
getSegments(val)
.filter((seg) => seg.index + seg.segment.length <= max)
.map((seg) => seg.segment)
.join(''),
}}
onChange={onChange}
onCompositionEnd={onCompositionEnd}
/>,
);
const input = container.querySelector('input')!;
fireEvent.compositionStart(input);
fireEvent.compositionUpdate(input, { target: { value: '你' } });
fireEvent.compositionUpdate(input, { target: { value: '你好' } });
fireEvent.compositionUpdate(input, { target: { value: '你好世' } });
fireEvent.compositionUpdate(input, { target: { value: '你好世界' } });
fireEvent.compositionEnd(input, { target: { value: '你好世界' } });
expect(input?.value).toEqual('你好世');
});

describe('cls', () => {
it('raw', () => {
const { container } = render(
Expand Down

0 comments on commit 3aba007

Please sign in to comment.