0

I have a time tracking project in React. What I'm trying to do is the following:

  • in each project I have a form to add activities and time;
  • I want to get the amount of time to be added and displayed at the end like a total - so if I have two activities, one with 2 hours, another with 3, "Total" should display the sum - 5 hours.

Some code:

  • Times component (contains the list of activities):
const Times = ({ times, onDelete }) => {
    return (
        <div>
            {times.length > 0 ? <p className="time-title">Time</p> : <p className="no-time-msg">Time: nothing here yet</p>}
            {times.map((time, index) => (<Time key={index} time={time} onDelete={onDelete}/>))}
            <TimeTotal />
       </div>
    )
}

  • Time component (contains activity, date and amount of time):

const Time = ({ time, onDelete }) => {
    return (
        <div className="hours-table">
            <h3>Activity: {time.activity}</h3>
            <h4>Date: {time.date}</h4>
            <TimeAmount time={time} />
            <FaTrash className="time-delete-icon" onClick={() => onDelete(time.id)}/>
        </div>
    )
}
  • TimeAmount component (contains the amount of time):
const TimeAmount = ({ time }) => {
    return (
        <div>
            <p value={time.time}>Time: {time.time} hour(s)</p>
        </div>
    )
}
  • TimeTotal component (should display the sum of the amounts of time):
const TimeTotal = ({ time }) => {

    const context = useContext(TimeContext)
    console.log(context)
    return <div className="time-total">Total: {context.times.length}</div>

}
  • In TimeTotal, I've used context, but it displays the number of activities, not the total amount of time, like I want.
1
  • Could you show us what console.log(context) prints? Commented Jul 27, 2021 at 13:22

2 Answers 2

2

context.times is an array containing activities, right? Well, in javascript, .length of an array represents the length of the array itself, so it represents how many activities you have. Javascript has no way to know what you're trying to sum or achieve.

You need to sum the durations yourself by iterating the array of activities, so you need to have:

const TimeTotal = ({ time }) => {
    const context = useContext(TimeContext);
    let totalDuration = 0;

    context.times.forEach((entry) => {
        totalDuration += entry.time;
    });

    return <div className="time-total">Total: {totalDuration}</div>
}

A shorter version would be:

const context = useContext(TimeContext);
const totalDuration = context.times.reduce((total, entry) => entry.time + total, 0)

const TimeTotal = ({ time }) => {
    const context = useContext(TimeContext)l
    const totalDuration = context.times.reduce((total, entry) => entry.time + total, 0);

    return <div className="time-total">Total: {totalDuration}</div>
}

You can read more about reduce here.

Sign up to request clarification or add additional context in comments.

4 Comments

And in what component should I add this ? And where should totalDuration be displayed ?
@George In TimeTotal, right? I updated my answer to reflect these changes.
I think it works, but instead of displaying the sum of the numbers, it just adds up to a big number - if I add 2 hours, it says 20, if I add 1 hour, it says 120 and so on - the newest number gets added to the front.
@George that's because your duration gets saved as a string, not as a number. If you "add" strings, you actually just concatenate values. You can fix this by having parseInt(entry.time) + total where the total is calculated or by making sure that the component that returns the time returns a number instead of a string.
1

You can use .reduce() method of Array, something like

const timesSum = context.times.reduce((acc, {time}) => {
  return acc + time
}, 0)

Take into account that I assumed time as numeric type. In real life you may need to cast time to number on manipulate it's value the way you need. Maybe you'll have to format timesSum.

Finally you'll have something like:

const TimeTotal = ({ time }) => {

    const context = useContext(TimeContext)
    console.log(context)
    
    const timesSum = context.times.reduce((acc, {time}) => {
      return acc + time
    }, 0);


    return <div className="time-total">Total: {timesSum}</div>

}

8 Comments

I get the same bug here - if I add 2 hours it says 02, and then, if I add 1 hour, it says 021 and so on.
What's in context.times array?
I need to see objects structure to fix the problem.
At least console.log().
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.