Today's question:
Create a React application "Code Review Feedback" that helps in tracking and managing feedback on various aspects of code quality.
Solution
In solving this, the first step is to assess the boilerplate code to know what was given and what is left to come up with. The boilerplate looked like this:
import React from "react";
const FeedbackSystem = () => {
return (
Readability
👍 Upvote
👎 Downvote
Upvotes: {0}
Downvotes: {0}
);
};
export default FeedbackSystem;
The boilerplate contains a card-div that shows one of the aspects of code quality that we will be managing. The div shows a heading and a voting system - upvote and downvote. So what will be needed is:
To make the card reusable, as there are 5 aspects of code quality to be managed.
To add a function that increases the total number of upvotes when the upvote button is clicked.
To add a function that increases the total number of downvotes when the downvote button is clicked.
To make the card reusable, an array will be created that we can map through the card div, such that the same div to display all the aspects that will be managed. This approach is more efficient than having to create 5 different divs for each aspect to be managed. The array created:
const aspects = [
{
id: 1,
heading: "Readability"
},
{
id: 2,
heading: "Performance"
},
{
id: 3,
heading: "Security"
},
{
id: 4,
heading: "Documentation"
},
{
id: 5,
heading: "Testing"
}
]
And the card div that the array was mapped through:
{aspects.map((aspect) =>(
{aspect.heading}
👍 Upvote
👎 Downvote
Upvotes: {0}
Downvotes: {0}
))}
);
};
export default FeedbackSystem;
The next step is to create the state variables to manage the vote count, and functions to increase the upvote and downvote when their respective buttons are clicked. To create the state variable:
const [votes, setVotes] = useState(
aspects.reduce((acc, aspect) => {
acc[aspect.id] = { upvotes: 0, downvotes: 0 };
return acc;
}, {})
);
To set the initial state, the reduce() method was used to transform the array to an object because the votes for each aspect will be updated using the id of that aspect, which is a more efficient approach. Then the upvotes and downvotes count were initialised to 0.
To increase the upvote count when the button is clicked:
const increaseUpvote = (id) => {
setVotes(prev => ({
...prev,
[id]: {
...prev[id],
upvotes: prev[id].upvotes + 1
}
}));
};
When updating votes, the previous state of the array is spread, and the count is updated by passing the id of that specific aspect. The same logic goes for the downvote count:
const increaseDownvote = (id) => {
setVotes(prev => ({
...prev,
[id]: {
...prev[id],
downvotes: prev[id].downvotes + 1
}
}));
};
The final step is to update the counter in the card div to take the default states for the upvotes and downvotes. The final code looks like this:
import React, { useState } from "react";
const aspects = [
{ id: 1, heading: "Readability" },
{ id: 2, heading: "Performance" },
{ id: 3, heading: "Security" },
{ id: 4, heading: "Documentation" },
{ id: 5, heading: "Testing" }
];
const FeedbackSystem = () => {
// Track votes for each aspect by ID
const [votes, setVotes] = useState(
aspects.reduce((acc, aspect) => {
acc[aspect.id] = { upvotes: 0, downvotes: 0 };
return acc;
}, {})
);
const increaseUpvote = (id) => {
setVotes(prev => ({
...prev,
[id]: {
...prev[id],
upvotes: prev[id].upvotes + 1
}
}));
};
const increaseDownvote = (id) => {
setVotes(prev => ({
...prev,
[id]: {
...prev[id],
downvotes: prev[id].downvotes + 1
}
}));
};
return (
{aspects.map((aspect, index) => (
{aspect.heading}
increaseUpvote(aspect.id)}
>
👍 Upvote
increaseDownvote(aspect.id)}
>
👎 Downvote
Upvotes: {votes[aspect.id].upvotes}
Downvotes: {votes[aspect.id].downvotes}
))}
);
};
export default FeedbackSystem;
That's all folks!