Skip to content

Commit 5497b81

Browse files
refactor: use string state for input control to avoid direct DOM manipulation
1 parent 4ec1b6c commit 5497b81

File tree

1 file changed

+35
-46
lines changed

1 file changed

+35
-46
lines changed

src/Pagination.tsx

Lines changed: 35 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,12 @@ const Pagination: React.FC<PaginationProps> = (props) => {
9090
Math.min(internalCurrent, calculatePage(undefined, pageSize, total)),
9191
);
9292

93-
const [internalInputVal, setInternalInputVal] = React.useState(current);
93+
const [internalInputVal, setInternalInputVal] = React.useState(
94+
String(current),
95+
);
9496

9597
useEffect(() => {
96-
setInternalInputVal(current);
98+
setInternalInputVal(String(current));
9799
}, [current]);
98100

99101
const hasOnChange = onChange !== noop;
@@ -129,31 +131,16 @@ const Pagination: React.FC<PaginationProps> = (props) => {
129131
return iconNode as React.ReactNode;
130132
}
131133

132-
function getValidValue(e: any): number {
133-
const inputValue = e.target.value;
134+
function getValidValue(inputValue: string): number {
134135
const allPages = calculatePage(undefined, pageSize, total);
135-
let value: number;
136136
if (inputValue === '') {
137-
value = inputValue;
138-
} else if (Number.isNaN(Number(inputValue))) {
139-
value = internalInputVal;
140-
} else if (inputValue >= allPages) {
141-
value = allPages;
142-
} else {
143-
value = Number(inputValue);
137+
return current;
144138
}
145-
return value;
146-
}
147-
148-
function getValidValueForFiltered(
149-
originalValue: string,
150-
filteredValue: string,
151-
): number | '' {
152-
// If the input was completely filtered out (non-numeric), return current value
153-
if (filteredValue === '' && originalValue !== '') {
154-
return internalInputVal;
139+
const numValue = Number(inputValue);
140+
if (Number.isNaN(numValue)) {
141+
return current;
155142
}
156-
return getValidValue({ target: { value: filteredValue } });
143+
return Math.min(Math.max(1, numValue), allPages);
157144
}
158145

159146
function isValid(page: number) {
@@ -177,40 +164,44 @@ const Pagination: React.FC<PaginationProps> = (props) => {
177164
| React.KeyboardEvent<HTMLInputElement>
178165
| React.ChangeEvent<HTMLInputElement>,
179166
) {
180-
const inputElement = event.target as HTMLInputElement;
181-
const originalValue = inputElement.value;
167+
const inputValue = (event.target as HTMLInputElement).value;
182168

183169
// Filter non-numeric characters for simple mode input
184-
const numericValue = originalValue.replace(/\D/g, '');
185-
if (numericValue !== originalValue) {
186-
inputElement.value = numericValue;
187-
}
170+
const numericValue = inputValue.replace(/\D/g, '');
188171

189-
const value = getValidValueForFiltered(originalValue, numericValue);
190-
// Handle empty string case
191-
const numValue = typeof value === 'number' ? value : internalInputVal;
172+
// Update display state
173+
const allPages = calculatePage(undefined, pageSize, total);
174+
const parsedValue = numericValue === '' ? 0 : Number(numericValue);
175+
const displayValue =
176+
parsedValue > allPages || (parsedValue < 1 && numericValue !== '')
177+
? String(Math.min(Math.max(1, parsedValue), allPages))
178+
: numericValue;
192179

193-
if (numValue !== internalInputVal) {
194-
setInternalInputVal(numValue);
195-
}
180+
setInternalInputVal(displayValue);
181+
182+
// Get valid value for page change
183+
const validValue = getValidValue(numericValue);
196184

197185
switch ((event as React.KeyboardEvent<HTMLInputElement>).keyCode) {
198186
case KeyCode.ENTER:
199-
handleChange(numValue);
187+
handleChange(validValue);
200188
break;
201189
case KeyCode.UP:
202-
handleChange(numValue - 1);
190+
handleChange(validValue - 1);
203191
break;
204192
case KeyCode.DOWN:
205-
handleChange(numValue + 1);
193+
handleChange(validValue + 1);
206194
break;
207195
default:
208196
break;
209197
}
210198
}
211199

212200
function handleBlur(event: React.FocusEvent<HTMLInputElement, Element>) {
213-
handleChange(getValidValue(event));
201+
const inputValue = (event.target as HTMLInputElement).value;
202+
const validValue = getValidValue(inputValue);
203+
setInternalInputVal(String(validValue));
204+
handleChange(validValue);
214205
}
215206

216207
function changePageSize(size: number) {
@@ -219,7 +210,7 @@ const Pagination: React.FC<PaginationProps> = (props) => {
219210
current > newCurrent && newCurrent !== 0 ? newCurrent : current;
220211

221212
setPageSize(size);
222-
setInternalInputVal(nextCurrent);
213+
setInternalInputVal(String(nextCurrent));
223214
onShowSizeChange?.(current, size);
224215
setCurrent(nextCurrent);
225216
onChange?.(nextCurrent, size);
@@ -235,10 +226,7 @@ const Pagination: React.FC<PaginationProps> = (props) => {
235226
newPage = 1;
236227
}
237228

238-
if (newPage !== internalInputVal) {
239-
setInternalInputVal(newPage);
240-
}
241-
229+
setInternalInputVal(String(newPage));
242230
setCurrent(newPage);
243231
onChange?.(newPage, pageSize);
244232

@@ -321,7 +309,8 @@ const Pagination: React.FC<PaginationProps> = (props) => {
321309

322310
function handleGoTO(event: any) {
323311
if (event.type === 'click' || event.keyCode === KeyCode.ENTER) {
324-
handleChange(internalInputVal);
312+
const validValue = getValidValue(internalInputVal);
313+
handleChange(validValue);
325314
}
326315
}
327316

@@ -411,7 +400,7 @@ const Pagination: React.FC<PaginationProps> = (props) => {
411400
style={styles?.item}
412401
>
413402
{isReadOnly ? (
414-
internalInputVal
403+
current
415404
) : (
416405
<input
417406
type="text"

0 commit comments

Comments
 (0)