I've been trying for a long time to implement the function to update my transactions, but I can't type in the input. I saw several similar questions on stackoverflow, but NONE helped me, I'm using modal and I believe the problem is because I'm receiving an object and I'm trying to manipulate another. However, I am not able to solve. Can anyone tell me how to proceed and explain a little how to avoid this?
My TransactionTable:
interface Transaction {
id: string;
title: string;
amount: number;
type: string;
category: string;
createdAt: string;
}
export function TransactionsTable() {
(...)
const [editingTransaction, setEditingTransaction] = useState<Transaction>()
function onOpenUpdateTransactionModal(transaction: Transaction) {
setEditingTransaction(transaction)
setIsUpdateTransactionModalOpen(true)
}
return (
(...)
<PencilSimple
size={20}
weight="fill"
onClick={() => onOpenUpdateTransactionModal(transaction)}
/>
(...)
<UpdateTransactionModal
isOpen={isUpdateTransactionModalOpen}
onRequestClose={onCloseUpdateTransactionModal}
editingTransaction={editingTransaction}
/>
)
}
My UpdateTransactionModal:
interface UpdateTransactionModalProps {
isOpen: boolean;
editingTransaction: Transaction | undefined;
onRequestClose: () => void;
}
export function UpdateTransactionModal({ isOpen, onRequestClose, editingTransaction }: UpdateTransactionModalProps) {
(...)
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
if(event.target.name === 'title') {
setTitle(event.target.value)
}
return(
(...)
<S.Container onSubmit={handleUpdateTransaction}>
<h2>Atualizar transação</h2>
<input
type="text"
placeholder="Título"
name="title"
value={editingTransaction?.title}
onChange={handleInputChange}
/>
<input
type="number"
placeholder="Valor"
value={editingTransaction?.amount}
onChange={e => setTitle(e.target.value)}
/>
)
}
}
I omitted a good part of the code, as I assumed it wasn't part of the resolution and didn't want to prolong the question, but if you want to see the whole code, it's here:
https://github.com/eltonsantos/eurorcamento
CodePudding user response:
import { ChangeEvent, FormEvent, useEffect, useState } from 'react';
import Modal from 'react-modal';
import incomeImg from '../../assets/income.svg';
import outcomeImg from '../../assets/outcome.svg';
import closeImg from '../../assets/close.svg';
import * as S from './styles';
import { useTransactions } from '../../hooks/useTransactions';
interface Transaction {
id: string;
title: string;
amount: number;
type: string;
category: string;
createdAt: string;
}
interface UpdateTransactionModalProps {
isOpen: boolean;
editingTransaction: Transaction | undefined;
onRequestClose: () => void;
}
export function UpdateTransactionModal({ isOpen, onRequestClose,
editingTransaction }: UpdateTransactionModalProps) {
const { updateTransaction } = useTransactions()
const [transaction, setTransaction] = useState({
title: editingTransaction?.title,
amount: editingTransaction?.amount,
type: editingTransaction?.type,
category: editingTransaction?.category
})
useEffect(() => {
setTransaction({...transaction, title: editingTransaction?.title,
amount: editingTransaction?.amount, type: editingTransaction?.type,
category: editingTransaction?.category})
},[editingTransaction])
console.log(editingTransaction)
console.log(transaction);
async function handleUpdateTransaction(event: any) {
event.preventDefault();
console.log("UpdID" editingTransaction)
// await updateTransaction()
//setEditingTransaction(editingTransaction)
}
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
setTransaction({...transaction, [e.target.name]: e.target.value});
}
return (
<Modal
isOpen={isOpen}
onRequestClose={onRequestClose}
overlayClassName="react-modal-overlay"
className="react-modal-content"
>
<button
type="button"
onClick={onRequestClose}
className="react-modal-close"
>
<img src={closeImg} alt="Fechar modal" />
</button>
<S.Container onSubmit={handleUpdateTransaction}>
<h2>Atualizar transação</h2>
<input
type="text"
placeholder="Título"
name="title"
value={transaction.title}
onChange={handleInputChange}
/>
<input
type="number"
placeholder="Valor"
value={transaction.amount}
onChange={handleInputChange}
/>
<S.TransactionTypeContainer>
<S.RadioBox
type="button"
isActive={transaction?.type === 'deposit'}
activeColor="green"
onClick={() => {setTransaction({...transaction, type: 'deposit'})}}
>
<img src={incomeImg} alt="Entrada" />
<span>Entrada</span>
</S.RadioBox>
<S.RadioBox
type="button"
isActive={transaction?.type === 'withdraw'}
activeColor="red"
onClick={() => {setTransaction({...transaction, type: 'withdraw'})}}
>
<img src={outcomeImg} alt="Saída" />
<span>Saída</span>
</S.RadioBox>
</S.TransactionTypeContainer>
<input
type="text"
placeholder="Categoria"
value={editingTransaction?.category}
onChange={handleInputChange}
/>
<button type="submit">Atualizar</button>
</S.Container>
</Modal>
) }
This is your updated code for updateTransactionModal. The Problems:
- You were passing value from editingTransactions to the input value field. That is why value was not updating.
- Secondly you were setting setTitle for all fields. either you can call setTitle, setAmount and so on for each field or you can simply create a transaction object and set them as i did in the code above.
- Third problem: Your value from editTransaction was undefined when the component loads for first time. and it gets updated a second later which leads to empty fields once you use the state value in your input fields. In order to solve that we applied a useEffect which updates the state with the updated editTransaction value. But you need to check why this is happening and avoid this. The editTransaction should be passed into the model as a prop and it should get the latest value on the first load there should be no need for useEffect. Hope I was able to solve.