fix(input): always synchronize external value and ignore changes (#336)

* fix(input): always synchronize external value and ignore changes

* feat(input): support imperative API to update
This commit is contained in:
witt
2020-07-19 17:52:12 +08:00
committed by unix
parent 4b9715b10e
commit dda76b2696
3 changed files with 60 additions and 8 deletions

View File

@@ -67,7 +67,7 @@ const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPr
const [selfValue, setSelfValue] = useState<string>(initialValue)
const [hover, setHover] = useState<boolean>(false)
const { heightRatio, fontSize } = useMemo(() => getSizes(size), [size])
const showClearIcon = useMemo(() => clearable && selfValue !== '', [selfValue, clearable])
const isControlledComponent = useMemo(() => value !== undefined, [value])
const labelClasses = useMemo(() => (labelRight ? 'right-label' : label ? 'left-label' : ''), [
label,
labelRight,
@@ -80,12 +80,12 @@ const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPr
theme.palette,
status,
])
const changeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
if (disabled || readOnly) return
setSelfValue(event.target.value)
onChange && onChange(event)
}
const clearHandler = (event: React.MouseEvent<HTMLDivElement>) => {
setSelfValue('')
onClearClick && onClearClick(event)
@@ -121,9 +121,18 @@ const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPr
)
useEffect(() => {
if (value === undefined) return
setSelfValue(value)
}, [value])
if (isControlledComponent) {
setSelfValue(value as string)
}
})
const controlledValue = isControlledComponent
? { value: selfValue }
: { defaultValue: initialValue }
const inputProps = {
...props,
...controlledValue,
}
return (
<div className="with-label">
@@ -139,7 +148,6 @@ const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPr
type="text"
ref={inputRef}
className={`${disabled ? 'disabled' : ''} ${iconClasses}`}
value={selfValue}
placeholder={placeholder}
disabled={disabled}
readOnly={readOnly}
@@ -147,11 +155,11 @@ const Input = React.forwardRef<HTMLInputElement, React.PropsWithChildren<InputPr
onBlur={blurHandler}
onChange={changeHandler}
autoComplete={autoComplete}
{...props}
{...inputProps}
/>
{clearable && (
<InputClearIcon
visible={showClearIcon}
visible={Boolean(inputRef.current && inputRef.current.value !== '')}
heightRatio={heightRatio}
disabled={disabled || readOnly}
onClick={clearHandler}

View File

@@ -185,6 +185,28 @@ Retrieve text input from a user.
`}
/>
<Playground
title="Imperative API"
desc="Update component in an uncontrolled way."
scope={{ Input, Spacer, Button }}
code={`
() => {
const ref = React.useRef(null)
const setChange = () => {
ref && (ref.current.value = Math.random().toString(32))
}
return (
<>
<Input initialValue="Hello" onChange={e => console.log(e.target.value)} ref={ref} />
<Spacer y={.5} />
<Button auto type="secondary" size="small"
onClick={setChange}>set value</Button>
</>
)
}
`}
/>
<Attributes edit="/pages/en-us/components/input.mdx">
<Attributes.Title>Input.Props</Attributes.Title>

View File

@@ -186,6 +186,28 @@ export const meta = {
`}
/>
<Playground
title="命令式 API"
desc="使用非受控方式更新组件。"
scope={{ Input, Spacer, Button }}
code={`
() => {
const ref = React.useRef(null)
const setChange = () => {
ref && (ref.current.value = Math.random().toString(32))
}
return (
<>
<Input initialValue="Hello" onChange={e => console.log(e.target.value)} ref={ref} />
<Spacer y={.5} />
<Button auto type="secondary" size="small"
onClick={setChange}>设置值</Button>
</>
)
}
`}
/>
<Attributes edit="/pages/zh-cn/components/input.mdx">
<Attributes.Title>Input.Props</Attributes.Title>