React useState – setting initial state to prefilled value

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.

Leave a Reply