Search code examples
javascriptreactjsdebugginginput-type-file

Input type="file" showing weird behavior when used along with another input type


I have an input type="file" and an input type="text". When I choose the file first and then put text in the input box and click the Add button, the picture doesn't show but when I put the text first and then choose the picture (file), it behaves normally.I think there's some problem in the inputKey That I have given. Here's a link from where I found this method http://robhoffmann.me/2016/03/12/Clearing-a-file-input-in-React/

What I am trying to do: I want to be able to choose an Image and type a product name which will then show on the screen. As soon as I click the Add button. I want both the inputs i.e. file type and text type to reset so that I can add the picture and Name of next product and so on..

function Admin(props){

    const [productName, setproductName] = React.useState("");

    let [productPicture, setproductPicture] = React.useState({file:null,inputKey:Date.now()});


    return (
        <div>
            <Link to="/">Go back</Link><br/><br/>
            <input type="file" onChange={(e)=>(productPicture=URL.createObjectURL(e.target.files[0]))} key={productPicture.inputKey}></input><br/>
            <input type="text" required placeholder="Product Name" onChange={(e)=>setproductName(e.target.value)} value={productName}></input><br/><br/>

<button type="Submit" onClick={(e)=>{props.AddInfo({productName,productPicture});setproductName("");setproductPicture({file:null,inputKey:Date.now()})}}>Add</button>
            <br/><br/>

            <div>
             {props.products.map((x)=>(<div>{x.name} {typeof x.picture === 'string' ? <img src={x.picture} alt="Product Picture" style={{width:"250px"}}></img>:""} </div>))}   
            </div>
        </div>
    )
}

export default Admin;

I expect the output to show the productName and productPicture when I click Add button but this only happens when I type in the text first and then choose the image/file and NOT when I do the vice-versa.


Solution

  • By doing this,

    <input type="file" onChange={(e)=>(productPicture=URL.createObjectURL(e.target.files[0]))} key={productPicture.inputKey}></input><br/>
    

    You are directly trying to mutate the state, productPicture=URL.createObjectURL(e.target.files[0]) which is wrong. Here you are not setting state. To set actual state you need to make use of setproductPicture setter function.

    <input type="file" onChange={setImage} key={productPicture.inputKey} />
    

    And setImage function should be,

    const setImage = (e) => {
      console.log(e.target.files[0].name);
      let file = e.target.files[0];  //Capture the file in variable otherwise event gets nullified and you won't get file.
      setproductPicture(prevState=>({
         ...prevState,
         file: URL.createObjectURL(file)
      }))
    }
    

    Demo

    Note: input is an empty tag, don't close it like <input></input>. You can just do this, <input />.