在 TextField 上 onBlur() 时触发 props.onChange()

问题描述

我正在构建一个组件 NumberField,该组件将在单击 (onFocus) 时删除 0,允许用户从空字段输入数字,并在焦点移出 (onBlur) 且该字段为空。

我想在 onBlur 被触发时从 props 调用 onChange 函数

NAME    CODE    MATERIAL
andy    a,b,d   paper,plastic,wood
roger       
danny   c,d     Metal,wood
cole    e       glass

我想“模拟”一个 onChange 事件调用的原因是因为我使用的是 Formik:

import * as React from 'react'

import {
    TextField,TextFieldProps
} from '@material-ui/core'

const NumberField: React.FC<TextFieldProps> = (props: TextFieldProps) => {
    const [state,setState] = React.useState<string>(`${props.value}`)

    React.useEffect(() => {
        setState(`${props.value}`)
    },[props.value])

    function onChange(event: React.ChangeEvent<HTMLInputElement>) {
        setState(event.target.value)
    }

    function onFocus() {
        if (state === '0')
            setState('')
    }

    function onBlur() {
        if (state === '')
            setState('0')

        const value = parseFloat(state || '0')
        if (value !== props.value) {
            // call props.onChange
        }
    }

    return (
        <TextField
            type="number"
            onChange={onChange}
            onFocus={onFocus}
            onBlur={onBlur}
            {...props}
        />
    )
}

export default NumberField

formik.handleChange 的签名是:

                    <NumberField
                        fullWidth
                        name="unit"
                        label="Unit"
                        value={formik.values.unit}
                        onChange={formik.handleChange}
                        error={formik.touched.unit && Boolean(formik.errors.unit)}
                        helperText={formik.touched.unit && formik.errors.unit}
                    />

我需要一个“假”的 React.ChangeEvent。有任何想法吗?我已经尝试了很多在 SO 上找到的东西(包括 useRef、dispatchEvent 和其他东西),但不工作而且很旧。也许事情已经改变了...

解决方法

这不是直接问题“如何模拟触发事件”的答案,而是在您使用 Material-UI 和 Formik 的情况下的替代解决方案。

import * as React from 'react'

import {
    TextField,TextFieldProps
} from '@material-ui/core'

type NumberFieldProps = TextFieldProps & {
    setValue: (value: number) => void
}

const NumberField: React.FC<NumberFieldProps> = (props: NumberFieldProps) => {
    const [state,setState] = React.useState<string>(`${props.value}`)
    const { value,...restProps } = props

    React.useEffect(() => {
        setState(`${props.value}`)
    },[props.value])

    function onChange(event: React.ChangeEvent<HTMLInputElement>) {
        setState(event.target.value)
    }

    function onFocus() {
        console.log('focus')
        if (state === '0')
            setState('')
    }

    function onBlur() {
        console.log('blur')
        if (state === '')
            setState('0')

        const value = parseFloat(state || '0')
        if (value !== props.value) {
            props.setValue(value)
        }
    }

    return (
        <TextField
            type="number"
            value={state}
            onChange={onChange}
            onFocus={onFocus}
            onBlur={onBlur}
            {...restProps}
        />
    )
}

export default NumberField
const MaterialForm: React.FC<Props> = (props: Props) => {
    const formik = useFormik({
        ...
    })

    return (
        ...
                <Grid item style={{ width: '100%' }}>
                    <NumberField
                        fullWidth
                        name="factor"
                        label="Factor"
                        value={formik.values.factor}
                        setValue={(value) => formik.setFieldValue('factor',value)}
                        error={formik.touched.factor && Boolean(formik.errors.factor)}
                        helperText={formik.touched.factor && formik.errors.factor}
                    />
        ...
    )
}

export default MaterialForm

https://formik.org/docs/api/formik#setfieldvalue-field-string-value-any-shouldvalidate-boolean--void

我仍然很想知道现在如何在 React 中模拟 onChange 事件!!