-1

I am new to React and for my first project I'm trying to build an expense-tracker, by Traversy Media on YT.

I've thought to expand project a little bit by adding a date component to it. My current output looks as follows: Image 1

And I want to look it as such: Image 2 (I hard-coded this output)

Basically I want Date component to only re-render if and only if no other component with same date exists. If component with same date exists the output should fall under it. I am confused with both logic of the problem and conditional rendering itself.

Here's what I've coded up until now:

const TransactionList = () => {

    const {transactions} = useContext(GlobalContext)

    return(
        <div>
            <h3>History</h3>
            <ul className='list'>
            {transactions.map(transaction => (
                <Transaction key={transaction.id} transaction={transaction}/>
                ))}
            </ul>
        <div>
    )
}

In above code transactions is an array which will be an initial-state of Global Context.

Code for component Transaction is as follows:

export const Transaction = ({transaction}) => {

  const { deleteTransaction } = useContext(GlobalContext)
  const sign  = transaction.amount > 0 ? '+' : '-' 

  return (
    <div>
        <ExpenseDate date={transaction.date} />
        <li className={transaction.amount > 0 ? 'plus' : 'minus' }>
            {transaction.text} <span>{sign}₹{Math.abs(transaction.amount)}</span>
        </li>
    </div>
  )
}

And code for ExpenseDate is as follows:

function ExpenseDate(props){
    const month = props.date.toLocaleString('en-US', {month: 'long'})
    const year = props.date.getFullYear();
    const day = props.date.getDate();

    return (
        <span className="expense-date">
            <span >{day}</span> <span >{month}</span> <span >{year}</span>
        </span>
    )
    
} 

My guess is the first step for conditional rendering will be to remove ExpenseDate as child of tag. The help will be very much appreciated. Thank You :))

3 Answers3

0

Few approaches you can consider doing in this case.

  1. change the structure of transactions to be grouped by date and have another component inside TransactionList which can render the group of ExpenseDate and Transaction

  2. Another approach is, if dates are sorted by default, then we can check if previous date is same as current date and hide the ExpenseDate component. https://codesandbox.io/s/tender-yonath-dy1pli-dy1pli?file=/src/components/TransactionList.js

First approach will be cleaner as it clearly defines the data in the shape we need

mtsandeep
  • 310
  • 1
  • 3
  • 11
  • I bow to your expertise. It was really helpful. At some point, when I have better grasp on React, I'll try the first approach. Thank you. –  अंशुल Jul 01 '22 at 03:16
  • Can you please describe more on approach one. I think answer from Omid down below somewhat captures what you're trying to direct me to. –  अंशुल Jul 01 '22 at 03:40
0

There are several ways to achieve this, but the easiest way would be to manage it with a state that contains a boolean.

So you need to import the useState hook from React first:

import { useState} from "react";

Then you need to set up a state inside your parent-component and use simple JavaScript to show it conditionally. In this example, the state is set to false by default:

export default function ParentComponent() {
    const [showComponent, setShowComponent] = useState(false);
    return (
        <div>
            {showcomponent && <ChildComponent />}
        </div>
    )

}

To manage the state itself, you can use the method of your state. In this case, it is called setShowComponent. Let's use it with a button that has a function assigned that handles the click and sets the state to true:

export default function ParentComponent() {
    const [showComponent, setShowComponent] = useState(false);
    handleClick() {
        setShowComponent(true);
    }
    return (
        <div>
            {showcomponent && <ChildComponent />}
            <button onClick={handleClick}>Hide/Show</button>
        </div>
    )

}

This will render the ChildComponent. Of course, you can apply any kind of logic to show the component conditionally.

Another alternative to manage states is to use Redux. Here you can find more information about states and about hooks in React.

Good luck.

  • 1
    Thanks for the help Jerome. I tried to go over it and realized it to be somewhat similar to the first answer by Sandeep, except the logic of applying boolean in here was in state, whereas he applied it as a prop. Ofcourse it was possible with states, thankyou for showing me how. Helped a lot. Keep up the good work! –  अंशुल Jul 01 '22 at 03:25
0

if you check out the following code you can find out how you should do this :

const date1 = new Date("Jun 30 2022");
const date2 = new Date("Jun 29 2022");

const transactions = [
  {
    title: "title1",
    date: date1
  },
  {
    title: "title2",
    date: date1
  },
  {
    title: "title3",
    date: date2
  },
  {
    title: "title4",
    date: date2
  }
];

function sortTransactions(transactions) {
  const sorted = {};

  transactions.forEach((transaction) => {
    const month = transaction.date.toLocaleString("en-US", { month: "long" });
    const year = transaction.date.getFullYear();
    const day = transaction.date.getDate();

    const key = `${day} ${month} ${year}`;
    const value = {
      title: transaction.title
    };

    if (sorted[key]) {
      sorted[key].push(value);
    } else {
      sorted[key] = [value];
    }
  });

  return sorted;
}

function App() {
  const sortedTransactions = sortTransactions(transactions);
  const dates = Object.keys(sortedTransactions);

  return (
    <div>
      {dates.map((date) => {
        return (
          <>
            <div>{date}</div>
            <ul>
              {sortedTransactions[date].map((transaction) => {
                return <li>{transaction.title}</li>;
              })}
            </ul>
          </>
        );
      })}
    </div>
  );
}

codesandbox : https://codesandbox.io/s/jolly-morse-nsb7c4

Omid Poorali
  • 169
  • 4
  • Thanks Omid. I'm really new to React and to the programming itself, but what I was able to figure out from your answer was that, I need to create another array/object which will store the dates independently and transactions array will have them as a reference. The logic seems amazing. It helped alot! –  अंशुल Jul 01 '22 at 03:37