I have a React component representing a form with inputs (Text, Number, Date). The date input has a default value – today
. I use this component for two functions: creating an object and editing an object. In the first case, all inputs are empty by default, except for the date input, which is set to today
. In the second case, the inputs receive default values from optional props (values
) that are passed to the component from the parent component’s state. The component is rendered on the page in two instances, one with values
passed and one without. Since the presence of values
is optional, I included a conditional operator in the default values of each input. In the case of the date input, it looks like this:
defaultValue={inputValues?.date ? inputValues.date : today}
In other cases, an empty string ''
is used instead of today
.
I expected that when the state changes, the component would re-render and insert the values
into the default inputs. In practice, this only happens with inputs that are initially empty, while the date input always has the value today
.
Through the console, I see that when the component is rendered, inputValue
= undefined (useState is set with empty brackets, so it’s not a surprise), so initially I assumed that the values
do not appear by the time of rendering. However, when the edit button is clicked, the correct values
are displayed in the console. In my understanding, at this point, the component should re-render and insert the values
according to the expression {inputValues?.date ? inputValues.date : today}
. However, in fact, the value of the date picker is today
, and the value of all other inputs is values
. If you replace today with an ''
in the expression, then when the edit function is called, the value of the date picker in the edit form is inputValues.date
, but the default value in the creation form is now empty, because today
is not set in this case.
This behavior is not exclusive to the date picker; any other input behaves in the same way if you replace ''
with any value in the expression. I would be very glad if you could explain this behavior and how to fix it.
Here is a test example:"
function App() {
const [values, setValues] = React.useState();
const change = () => setValues({ name: 'name', date: '2023-11-28' });
return (
<Child values={values} change={change} />
);
}
function Child({ values, change }) {
console.log(values);
return (
<div className="container">
<button type="button" onClick={change} >clickMe</button>
<input type="text" defaultValue={values?.name ? values.name : ''} />
<input type="date" defaultValue={values?.date ? values.date : '2023-11-20'} />
</div>
);
}
const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);
2
Answers
The issue you’re facing is related to the fact that the defaultValue attribute is only set once when the component initially renders. Changing the values prop doesn’t trigger a re-render of the child component, so the defaultValue remains unchanged.
You can use default values for every prop that is given to the component. I’ve altered the structure of your code a bit, making it more readable and easier to use.
This way, the inputs change the value on their own, allowing the user to edit the contents of the input. And when the user clicks the "clickMe" submit button, the component
App
will get these values and allows you for further implementation. For now, I’ve made it so that<App />
just dumps the value into<code id="vardump" />
, so you will be able to see the difference easily.Sandbox: https://codesandbox.io/p/sandbox/reactjs-answer-xtqfc3