1
// ExpenseForm.tsx

interface ExpenseData {
  enteredTitle: string;
  enteredAmount: number;
  enteredDate: string;
}

const ExpenseForm = (props) => {
  const [userInput, setUserInput] = useState<ExpenseData>({
    enteredTitle: "",
    enteredAmount: 10,
    enteredDate: "",
  });

  const { register, handleSubmit, resetField } = useForm<ExpenseData>();

  const onValid = (data: ExpenseData) => {
    setUserInput(data);
    resetField("enteredAmount");
    resetField("enteredDate");
    resetField("enteredTitle");
  };

};
// NewExpense.tsx
const NewExpense = (props) => {
  const saveExpenseDataHandler = (enteredExpenseData) => {
    const expenseData = {
      ...enteredExpenseData,
      id: Math.random().toString(),
    };
    console.log(expenseData); // I want to see this.
    props.onAddExpense(expenseData);
  };
  return (
    <div className="new-expense">
      <ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />
    </div>
  );
};

//App.tsx
const App = () => {
  const expenses = [
    {
      id: "xxxx",
      title: "xxx",
      amount: xxxx,
      date: new Date(2022, 5, 16),
    },
  ];

  const addExpenseHandler = (expense) => {
    console.log(expense);
  };

  return (
    <div>
      <NewExpense onAddExpense={addExpenseHandler} />
    </div>
  );
};

I'm using react with typescript in Udemy Course.

I want to send onSaveExpenseData in NewExpense.tsx to ExpenseForm.tsx. How do I define type onSaveExpenseData in interface?

Also I want to using reset

I tried to onSaveExpenseData:()=>void, but it doesn't work.

JeongHaSeung
  • 393
  • 6
  • 12

2 Answers2

1

You can export a type for expense.

export interface Expense {
  id: string;
  title: string;
  amount: number;
  date: Date;
}

Then in your function you can type expense

const addExpenseHandler = (expense: Expense) => {
    console.log(expense);
};

In your NewExpense.tsx you can type its props to this:

interface NewExpenseProps {
  onAddExpense: (e: Expense) => void;
}

export const NewExpense = ({ onAddExpense }: NewExpenseProps) => {
  const saveExpenseDataHandler = (enteredExpenseData: Expense) => {
    const expenseData = {
      ...enteredExpenseData,
      id: Math.random().toString(),
    };
    console.log(expenseData); // I want to see this.
    onAddExpense(expenseData);
  };

  return (
    <div className="new-expense">
      <ExpenseForm onSaveExpenseData={saveExpenseDataHandler} />
    </div>
  );
};

In your expense form you can do the same thing:

interface ExpenseFormProps {
  onSaveExpenseData: (v: Expense) => void;
}

export const ExpenseForm = ({ onSaveExpenseData }: ExpenseFormProps) => {
  console.log(onSaveExpenseData);
  return <div>ExpenseForm</div>;
};
dlarroder
  • 61
  • 3
  • Adding the type directly on the prop argument is not best practice. Your type definition won't include `children`. Check my comment on how to better define the props on a React functional component. – Tea_Lover_418 Jun 08 '22 at 07:45
  • @Tea_Lover_418 I don't think thats the case anymore in React 18, please see https://stackoverflow.com/a/71809927 from dan abramov himself :) – dlarroder Jun 27 '22 at 11:26
  • What a weird change, thanks for pointing that out. Currently I'm sticking with 17 anyways because I've had some instability issues with 18. – Tea_Lover_418 Jun 27 '22 at 16:41
0

You need to define your props on the react component. Also the type you wrote was almost correct, but it takes 1 argument that you were missing.

The easiest way to do this is like this:

import { FC } from 'react';

interface Props {
   onSaveExpenseData: (_: Expense) => void
}

const ExpenseForm: FC<Props> = ...your current function

FC is the react type for FunctionalComponent. It will define the props and return value for you. The < Props > is a generic you pass to this type. It looks pretty complex but you don't have to fully understand it to use it.

Tea_Lover_418
  • 308
  • 2
  • 10