I have a form with an input component that may be empty or it may be prefilled with some data. It’s also a controlled component so I keep track of the value of the input field using React’s useState
.
Something like this:
export const MyComponent = props => {
const [value, setValue] = useState(props.value || null)
return <input value={value} type="text" />
}
In reality, however, prefilling the initial state of the input field is a bit more complex as there is a bit more drilling I have to do in the props
argument and some checks that I have to do before initializing the default value.
Now, I can do this:
export const MyComponent = props => {
const [value, setValue] = useState(null)
useEffect(() => {
if (props.one?.two?.[0].value !== 0) {
const option = props.someList.find(x => x.id === props.one.two[0].value)
if (option)
setValue(option)
}
}, [])
return <input value={value} type="text" />
}
But I get warnings saying that useEffect has missing dependencies and I should add the props
drilldown to my dependencies array. But I don’t want to have the useEffect
run every single time that is updated. I just want to have it run once upon component mount / initialization and that’s it.
Is there a way to do my complicated initialization without having to use useEffect
?
>Solution :
The initial value to useState
can be a function. You can put the logic there instead of in a useEffect
.
const [value, setValue] = useState(getInitialValue)
const getInitialValue = () => {
if (props.one?.two?.[0].value !== 0) {
const option = props.someList.find(x => x.id === props.one.two[0].value)
if (option) {
return option;
}
}
return null;
}
Notice that it was not useState(getInitialValue())
. Passing the function for React to call means it will only be called once. Calling it yourself will cause it to happen every render.