The controlled component's value is bound to the React state. Any changes to the component value are written to the React state using event handlers like onChange. Therefore, the component value is available through the React state. On the other hand, the uncontrolled component is independent of the React state. The DOM handles the value and is accessible through the DOM.
Let's look at a few HTML elements and how we can use them as controlled components.
The
import { useState } from "react"
export const App = () => {
const [name, setName] = useState<string>()
const handleReset = () => {
setName("")
}
return(
<>
<div>
<input value={name} onChange={(e) => setName(e.target.value)}/>
</div>
<div>{name}</div>
<br/>
<div>
<button onClick={handleReset}>Reset</button>
</div>
</>
)
}
export default App
The
import { useState } from "react"
export const App = () => {
const [countryName, setCountryName] = useState<string>()
const selectOptions = [{val:"0", label:"Select"},{val:"1", label:"USA"},{val:"2", label:"Canada"}]
return(
<div>
<select value={countryName} onChange={(e) => setCountryName(e.target.value)}>
{selectOptions.map((option) => {
return <option value={option.val} key={option.val}>{option.label}</option>
})}
</select>
</div>
<div>
<button onClick={() => setCountryName("2")}>Select Canada</button>
</div>
<div>
{countryName && selectOptions.filter((country) => {
return country.val === countryName
})[0].label}
</div>
)
}
export default App
Like select element, the
import { useState } from "react"
export const App = () => {
const [selected, setSelected] = useState<string[]>()
const selectOptions = [
{val:"1", label:"USA"},
{val:"2", label:"Canada"},
{val:"3", label:"Japan"},
{val:"4", label:"Mexico"}
]
const handleChange = (target: HTMLSelectElement) => {
setSelected(Array.from(target.selectedOptions, option => option.value))
selectOptions.filter((option) => {return option.label})
}
const selectCanada = () => {
setSelected(["2"])
}
return(
<>
<select name="multiSelect" multiple={true} value={selected} onChange={(e) => handleChange(e.target)}>
{selectOptions.map((option) => {
return <option value={option.val} key={option.val}>{option.label}</option>
})}
</select>
<br/>
<button onClick={selectCanada}>Select Canada</button><br/>
<ol type="1">
{selected?.map((val) => {
return <li>{selectOptions.filter((option) => {return option.val === val})[0].label}</li>
})}
</ol>
</>
)
}
export default App
Note that in Radio button groups, we don't directly bind the radio button value to the state variable. To check a particular radio button manually, we check if the state variable value is equal to each radio button value.
import { useState } from "react"
export const App = () => {
const [radioButtonName, setRadioButtonName] = useState<string>()
const selectUSA = () => {
setRadioButtonName("USA")
}
return(
<div style={{margin: 24}}>
<div>
<label style={{width: 76}} htmlFor="">USA</label>
<input value="USA" checked={radioButtonName === "USA"} type="radio" onChange={(e) => setRadioButtonName(e.target.value)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Canada</label>
<input value="Canada" checked={radioButtonName === "Canada"} type="radio" onChange={(e) => setRadioButtonName(e.target.value)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Japan</label>
<input value="Japan" checked={radioButtonName === "Japan"} type="radio" onChange={(e) => setRadioButtonName(e.target.value)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Mexico</label>
<input value="Mexico" checked={radioButtonName === "Mexico"} type="radio" onChange={(e) => setRadioButtonName(e.target.value)}/>
</div>
{radioButtonName && <div style={{marginTop: 24}}>{radioButtonName} Selected</div>}
<br/>
<button onClick={selectUSA}>Select USA</button><br/>
</div>
)
}
export default App
Like the radio button example above, we don't directly bind the check box value to the state variable. Instead, we use a handler method to update the state variable when the checkbox is checked and unchecked.
import { useState } from "react"
export const App = () => {
const [checkBoxValue, setCheckBoxValue] = useState<string>()
const subscribeToNewsLetter = (val: HTMLInputElement) => {
setCheckBoxValue((prev) => val.checked ? val.value : "N")
}
return(
<div style={{margin: 24}}>
<div>
<label style={{width: 224}}>Subscribe to news letter : </label>
<input type="checkbox" value="Y" onChange={(e) => subscribeToNewsLetter(e.target)}/>
</div>
{checkBoxValue && <div style={{marginTop: 24}}>{checkBoxValue} Selected</div>}
</div>
)
}
export default App
We use a string array to hold the checked checkboxes values. Check and uncheck are determined by the event, and add or delete the checkbox value from the state array accordingly.
import { useState } from "react"
export const App = () => {
const [checkBoxValues, setCheckBoxvalues] = useState<string[]>([])
const subscribeToNewsLetter = (target: HTMLInputElement) => {
if(target.checked){
setCheckBoxvalues((prev) => {
return [...prev, target.value]
})
}
else{
setCheckBoxvalues((prev) => {
return prev.filter((country) => {
return country !== target.value
})
})
}
}
return(
<div style={{margin: 24}}>
<div>
<label style={{width: 76}} htmlFor="">USA</label>
<input type="checkbox" value="USA" onChange={(e) => subscribeToNewsLetter(e.target)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Canada</label>
<input type="checkbox" value="Canada" onChange={(e) => subscribeToNewsLetter(e.target)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Japan</label>
<input type="checkbox" value="Japan" onChange={(e) => subscribeToNewsLetter(e.target)}/>
</div>
<div>
<label style={{width: 76}} htmlFor="">Mexico</label>
<input type="checkbox" value="Mexico" onChange={(e) => subscribeToNewsLetter(e.target)}/>
</div>
<div style={{marginTop: 24}}>Selected options</div>
<ol type="1">
{checkBoxValues?.map((val) => {
return <li>{val}</li>
})}
</ol>
</div>
)
}
export default App