Reputation: 995
I am using React Hooks to handle a simple form. I receive 'transaction' object as a prop and I want to set input values based on this object, because I am trying to update this 'transaction'
As you can see below I am trying to set my description inputs value based on 'transaction' object, which I receive as prop
//TransactionsForm.js
const TransactionsForm = ({ onSubmit, transaction }) => {
const [values, setValues] = useState({
description: transaction.description
})
const handleChange = event => {
const { name, value } = event.target
setValues({ ...values, [name]: value })
}
return (
<form>
<input
type="text"
placeholder="description"
name="description"
value={values.description}
onChange={handleChange}
/>
<button>Submit</button>
</form>
)
}
this 'transaction' object looks like this initially:
{
id: null,
description: '',
transactionType: '',
date: '',
category: '',
amount: ''
}
but then I update it, when the user clicks the edit button and set it to the clicked transaction object to pass to my TransactionsForm.js and thus update the form input values based on this.
if I set my input value like this
<input
type="text"
placeholder="description"
name="description"
value={transaction.description} // like this it's working, but when I use values.description the value is not updating
onChange={handleChange}
/>
Upvotes: 0
Views: 2322
Reputation: 4977
I guess you have an issue with updating values when TransactionsForm
props change. useState
only sets the initial value on the first render and doesn't update it when props change. You need to do it manually:
const TransactionsForm = ({ onSubmit, transaction }) => {
const [values, setValues] = useState({
description: transaction.description
});
useEffect(() => setValues(
oldValues => (
{...oldValues, description: transaction.description}
)
), [transaction.description]);
...
useEffect
will be called on initial render and every time transaction.description
gets a new value. Since setValues
receives a new object you'll get unnecessary extra render after the initial one. To avoid that you can store only the description
in your state:
const [descripton, setDescription] = useState(transaction.description);
If you really need a complex state structure consider using useReducer and store "oldProps" with useRef:
const TransactionsForm = ({ onSubmit, transaction }) => {
const [values, setValues] = useState({
description: transaction.description
});
const oldDescription = useRef(transaction.description);
useEffect(() => {
if (oldDescription.current !== transaction.description) {
oldDescription.current = transaction.description;
setValues(
oldValues => (
{...oldValues, description: transaction.description}
)
);
}
}, [transaction.description]);
...
Upvotes: 4