2

I'm trying to submit a form with react & typescript but keep getting errors.

My terminal outputs this error Type 'File | undefined' is not assignable to type 'string | number | readonly string[] | undefined' and if I try to upload a file the website crashes with this warning and error.

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.

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 HTMLInputElement.set [as value]

-- EDIT --

So after debugging for a while I have discovered that if I just pass an empty string into the value attribute then the form submits and my image / file is processed and works fine. So the issue lyes with the setting of the value attribute which mean it's this error I need to fix! 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 HTMLInputElement.set [as value]

I have the following input component

import React, { useRef } from "react";
import { styled } from "../../../stitches.config";

const Input = styled("input", {
    width: "100%",
    height: "45px",
    background: "$white",
    color: "$black",
    textIndent: "10px",
    border: "1px solid $grey",
    borderRadius: "5px",
    paddingRight: "10px",
});

interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
    onChange: React.ChangeEventHandler<HTMLInputElement>;
}

export default ({ type, name, value, required, onChange }: Props) => {
    const input = useRef<HTMLInputElement>(null);

    return (
        <Input
            type={type}
            name={name}
            value={value}
            ref={input}
            required={required}
            onChange={(e) => onChange(e)}
        />
    );
};

My form component looks like this

interface Props {
    auth: any;
}

interface FormProps {
    title: string;
    intro: string;
    content: string;
    image: File | undefined;
    published_date: string;
}

const Create = ({ auth }: Props) => {
    const { data, setData, processing, post, errors } = useForm<FormProps>({
        title: "",
        intro: "",
        content: "",
        image: undefined,
        published_date: "",
    });

    const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
        if (e.target.files) {
            setData("image", e.target.files[0]);
            console.log(data.image, " image");
        }
    };

    const onSubmit = (e: React.SyntheticEvent) => {
        e.preventDefault();
        post("/admin/blogs/create", {
            preserveScroll: true,
        });
    };

    return (
        <Authenticated auth={auth} css={{ background: "$light" }}>
            <Container css={{ maxWidth: "1200px", py: "100px" }}>
                <Heading size="charlie">Create a post</Heading>
                <Errors errors={errors} />

                <form onSubmit={onSubmit} noValidate>
                   
                    ....

                    <Row>
                        <Label input={"image"} value={"Image"} required={true}>
                            <Input
                                type="file"
                                name="image"
                                value={data.image}
                                required={true}
                                onChange={handleFile}
                            />
                            {errors.image && (
                                <InputError error={errors.image} />
                            )}
                        </Label>
                    </Row>
                    <Row>
                        <Button
                            processing={processing}
                            type={"submit"}
                            color={"primary"}
                        >
                            Publish
                        </Button>
                    </Row>
                </form>
            </Container>
        </Authenticated>
    );
};

export default Create;
2
  • Does useForm() set the props to the component's state? Commented Mar 20, 2022 at 18:21
  • @SomaM. yes it does, the input data is stored in the data state. Sorry forgot to mention that I'm using inertia.js form helper inertiajs.com/forms Commented Mar 20, 2022 at 18:23

1 Answer 1

2

Since the value of a file input <input type="file" /> is read-only, it can only be an uncontrolled element, which means it does not take value prop. docs

In your custom input element, you may want to check the type before passing the value prop.

Sign up to request clarification or add additional context in comments.

1 Comment

So simple, I didn't even realise I don't need the value on the field input! Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.