Warning: A component is changing a controlled input of type file

Viewed 680

In an application using react, I have a form with radio input, which chooses which component will render, but when I change the radio option this warning shows up -

"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"

Form

    import React, { useState } from "react";
    export default () => {
        const [link, setLink] = useState("");
        const [arquivo, setArquivo] = useState("");
        const [forma_envio, setFormaEnvio] = useState("");
       
       
        return(
        <React.Fragment>
            <div className="form-check ">
                <input
                    type="radio"
                    className="form-check-input"
                    name="forma"
                    id="forma1"
                    value="File"
                    checked={forma_envio === "File"}
                    onChange={(e) => {
                        setFormaEnvio(e.target.value);
                    }}
                />
            </div>
             <div className="form-check ">
                <input
                    type="radio"
                    className="form-check-input"
                    name="forma"
                    id="forma2"
                    value="Link"
                    checked={forma_envio === "Link"}
                    onChange={(e) => {
                        setFormaEnvio(e.target.value);
                    }}
                />
            </div>
            {forma_envio === "File" ? (
                <input
                    type="file"
                    className="form-control-file form-control"
                     id="arquivo"`
                    onChange={(e) => {
                        e.preventDefault();
                        handleUpload(e.target.files[0]);
                    }}
                />
            ) :forma_envio === "Link" (
                <input
                    value={link}
                    type="text"
                    className="form-control"
                    id="link"
                    onChange={(e) => {
                        e.preventDefault();
                        setLink(e.target.value);
                    }}
                />
            ):
            ("")}
        </React.Fragment>
    );
}

All states are starting with "".

Everything works fine, but I still can't figure how to fix this warning.

1 Answers

Make sure the initial value of link is not null or undefined, but an empty string, like:

// const [link, setLink] = React.useState() //  will cause the warning
const [link, setLink] = React.useState('') // correct

EDIT: After the question was edited, I noticed the problem:

input tags of type "file" MUST BE UNCONTROLLED. You should not pass value or onChange to it. Instead, you should pass a reference and attach it to the input.

const arquivo = useRef(null);

return (
    <React.Fragment>
        // ...
        <input
            type="file"
            ref={arquivo}
            id="arquivo"
        />
    </React.Fragment>
)

This is also a rare situation in which you want to hide a DOM node instead of avoiding the rendering. The File object is stored directly on the DOM, so you must keep this DOM node around, otherwise you will lose the selected files.

<input
    type="file"
    ref={arquivo}
    id="arquivo"
    style={{ display: forma_envio !== "File" && "none" }}
/>

Complete code at CodeSandbox, without warnings.

Related