G
G
glem13372020-05-04 18:36:01
React
glem1337, 2020-05-04 18:36:01

Why is Redux Field not firing onChange?

I call the Field component from redux-form:

<Field
                id={'form__file'}
                className={'form__file form__control'}
                name={'photo'}
                type={'file'}
                label={'Upload your photo'}
                accept={'image/jpeg,image/jpg'}
                component={FileInput}
                onChange={onFileInputChange}
            />


It in turn renders FileInput which renders Form.File from react-bootstrap:
export class FileInput extends Component {

    onChange = e => { // это никогда не срабатывает
        e.preventDefault();
        const { input: { onChange } } = this.props;
        onChange(e.target.files[0]);
    };

    render() {

        let {meta: {touched, error}, ...props} = this.props;

        return (
            <>
                <Form.File
                    custom
                    {...props.input}
                    id={props.id}
                    className={props.className}
                    label={props.label}
                    onChange={this.onChange}
                    type={props.type}
                    accept={props.accept}
                />
                {touched && error && (
                    <Form.Text className="form__error form__text">
                        {error}
                    </Form.Text>
                )}
            </>
        )
    }
};


The onFileInputChange handler that should fire:
onFileInputChange = (e) => {
        e.preventDefault();
        this.setState({photo: e.target.files[0]});
        console.log(e.target.files[0]);
    };


The problem is that when you click on the file selection, the application crashes, that is, a white screen and an empty #root element. It also throws three errors:
1) The above error occurred in the component
2) Warning: A component is changing an uncontrolled input of type file to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
3) Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

At the same time, if I place the field not through Field from redux-form, but directly into the form, then the handler fires, and everything is OK:
<Form.File
                id={'form__file'}
                className={'form__file form__control'}
                name={'photo'}
                type={'file'}
                label={'Upload your photo'}
                accept={'image/jpeg,image/jpg'}
                onChange={onFileInputChange}
                custom
            />


All other fields are validated and handlers work without problems. If you need the whole code, I'll post it.
In the guides that tell you how to do this, in fact everything is the same.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
G
glem1337, 2020-05-05
@glem1337

Found what the problem is. The FileInput that was rendered by Field through the {...props.input} specification set the value for the field, but this cannot be done. You need to change it like this:

export class FileInput extends Component {

    onChange = e => { 
        e.preventDefault();
        const { input: { onChange } } = this.props;
        onChange(e.target.files[0]);
    };

    render() {

        let {meta: {touched, error}, input: {value}, ...props} = this.props; // достаем value из props.input

        return (
            <>
                <Form.File
                    custom
                    {...props.input}
                    id={props.id}
                    className={props.className}
                    label={props.label}
                    onChange={this.onChange}
                    type={props.type}
                    accept={props.accept}
                />
                {touched && error && (
                    <Form.Text className="form__error form__text">
                        {error}
                    </Form.Text>
                )}
            </>
        )
    }
};

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question