Search code examples
reactjsreact-component

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


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.


Solution

  • 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.