Ali
Ali

Reputation: 1759

How to set the value of inputs with ReactJS hooks?

I want to fill the inputs value of a form with default values once the modal is opened

I did it with pure javascript using document.getElementById(textId).value='some value as follow:

  for(var i=0; i<details_data.length;i++){
     let textId='text'+i;
     let amountId='amount'+i;
     document.getElementById(textId).value=details_data[i].text
  }

This worked fine. but I want to know how to do it with React since I don't believe this is a best practice.

what i tried is to set the input value like this:

<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>

But this woudn't let me change the value of the input. it just set the default value, and when i type in the input the value woudn't change as I want.

This is my code

const [details_data,set_details_data]=useState([
    {'text':'','amount':''}
])
// called this function on `onChange` and store the data in `details_data`
function details_handler(e){
    let name=e.target.name;
    let value=e.target.value;
    details_data[this][name]=value;
    set_details_data(details_data);
  }

JSX:

(In my case user can add inputs as many as he wants,That's why I put the inputs in a the mapping loop)

  {
    details_data.map((el,index) => {
        let textId='text'+index;
        let amountId='amount'+index;
        return (
            <div key={index}>
                <input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
                <input name='amount' id={amountId} onChange={details_handler.bind(index)}/>
            </div>
            );
      })
  }

Upvotes: 3

Views: 5772

Answers (2)

Steve Owens
Steve Owens

Reputation: 67

Its so difficult to understand why so many offer bad advice when it comes to setting the value of a React input. All of this business with implementing onChange events because when you set the value of the text input you can't edit it is so very easy to overcome and you don't need hooks for that. Using the onChange event bandaid, simply generates tons of events that simply are not needed.

Consider the following Custom control:

export default function TextInput({name, initialValue}:
    {name:string, initialValue?:string}) {
    return(<input type="text" name={name} defaultValue={initialValue}/>)
}

Right off the bat, when this control renders the initial value becomes the control value and then the control can be edited like any other web form input.

If you want the control to respond to hooks then in the parent form you can use State as follows:

export default function ParentForm() {
    const values = ["value 1", "value 2", "value 3"];
    const [index, setIndex] = useState(0);
    const [someValue, setSomeValue] = useState(values[index]);

    const modTheValue = (event: any) =>{
       if(index < 2)
           setIndex(index+1);
       else
           setIndex(0);
    }

    useEffect(() => {
       setSomeValue(values[index])
    },[index])


    return(
        <form>
            <TextInput name="someInput" initialValue={someValue}/>
            <button type="button" onclick={modTheValue}>Change It</button>
        </form>
    )

}

Here when you click Change it, the index state variable gets updated. Then sometime later useEffect detects a change in index, and then calls setSomeValue with a new value, this causes the TextInput to re-render and gets the current someValue as the initial value.

Upvotes: 0

Karthik
Karthik

Reputation: 1131

 useEffect(() => {
     if(detailsProps) {
         set_details_data(detailsProps);
     }
 }, [detailsProps])

where your detailsProps (data from the api) will look something like this

 detailsProps = [
    {'text':'text1','amount':'100'},
    {'text':'text2','amount':'200'}
 ]

onChange Function

const details_handler = (event, index) => {
   const items = [...details_data];
   items[index][event.target.name] = event.target.value;
   set_details_data(items);
}

your view

 {
details_data.map((el,index) => {
    return (
        <div key={index}>
            <input name='text' value={el.text} onChange={(e) => details_handler(e, index)}/>
            <input name='amount' value={el.amount} onChange={(e) => details_handler(e, index)}/>
        </div>
        );
  })
}

Upvotes: 3

Related Questions