How to call a function every time component is displayed? - reactjs

I am new to React and working on a project to get a better grasp of all its concepts. I am currently building a time-tracking application, that allows users to track time across tasks from different projects.
I am using Redux and storing in my app state a list of Projects each with a list of Tasks. Each task has a totalDurationInSeconds property.
I want to create a Reports page. Currently on the reports page, I only want to display the total duration in seconds across all projects. When I first start the application, the time is 0. If I add a task to one of the projects, the time gets updated.
However, when I add a second task to either the same project or a different project, the value does not get updated and it still only displays the duration of the first task.
const ReportsPage: React.FC<Props> = (props): React.ReactElement => {
const [totalDuration, setTotalDuration] = useState(0);
useEffect(() => {
for (let i = 0; i < props.projects.length; i++) {
for (let j = 0; i < props.projects[i].tasks.length; i++) {
setTotalDuration(totalDuration + props.projects[i].tasks[j].totalDurationInSeconds);
}
}
}, [])
return (
<div>
<p>Total time spent across all projects : {totalDuration}</p>
</div>
);
};
My component is connected to the ReduxStore and Props is of type StateProps & ReportsPageProps.

Your inner loop condition and increment is using i instead of j
this is what you want:
for (let i = 0; i < props.projects.length; i++) {
for (let j = 0; j < props.projects[i].tasks.length; j++) {
setTotalDuration(totalDuration + props.projects[i].tasks[j].totalDurationInSeconds);
}
}

When useEffect function used without any dependency it executed one time, but you want the totalDuration will update when any task added.
useEffect(() => {
for (let i = 0; i < props.projects.length; i++) {
for (let j = 0; j < props.projects[i].tasks.length; j++) {
setTotalDuration(totalDuration + props.projects[i].tasks[j].totalDurationInSeconds);
}
}
}, [props.projects])

Related

Adding another check property to select default rows on antd table

Currently i have this code on my api call to add a check property (list) (based on api called data "resRole" and "res") which can be used inside of rowSelection to select all the default checked row.
However, now i have another table which I need to do the same thing. Just that instead of using resRole, now I will use resProject. Which i need to first add a key to, before i add a checkProject in "res".
As such, i updated the check to checkRole and intend to put in an additional checkDept (list) in the getAllUserRole's res.data.
Looking at my code, I do not know where I can implement it. It seems like I have to create it inside of the getDataUserRole() function but that seems too messy. And might cause some async issues.
Below is the code:
async function getDataProject() {
let resProject = await getAllProject();
if (resProject) {
setDataSourceProject(resProject.data);
}
}
async function getDataUserRole() {
let resRole = await getAllRoles();
if (resRole) {
//Add a key to every Role
for (var i = 0; i < resRole.data.length; i++) {
resRole.data[i]["key"] = i;
}
setDataSourceRole(resRole.data);
let res = await getAllUserRole();
if (res) {
console.log("getAllUserRole =", res);
for (var i = 0; i < res.data.length; i++) {
//add "check" to every email in the array
res.data[i]["checkRole"] = [];
//loop through all the roleIds array in each email
for (var j = 0; j < res.data[i].roleIds.length; j++) {
//if roleIds is not empty
if (res.data[i].roleIds.length != 0) {
//loop through all Role from getAllRoles and check if any roleIds match the Role. If match push the key of the Role into check
for (var k = 0; k < resRole.data.length; k++) {
if (res.data[i].roleIds[j] == resRole.data[k].id) {
res.data[i]["checkRole"].push(resRole.data[k].key);
}
}
}
}
}
//If groupChange (groupChange is state for storing value of radio button) is null, return untransformed data
if (!(groupChange)) {
setDataSourceUserRole(res.data);
}
//If groupChange has value, call the function with the state value as a parameter
else {
var treeData = groupData(res.data, groupChange)
setDataSourceUserRole(treeData);
}
}
}
}
Instead of Using it inside getDataUserRole(). Use it inside getAllUserRole(). and once you get your result just add additional data with the role and send it back to one function.
If you want to call it separately so then you to depend it one function on another because due to async it will not work properly

Discord.js Pagination Limit

Basically I'm trying to create a pagination limit per embed, So if there are 10+ values then there would be separate embeds per 10. So far I was doing, But it just spams it and doesn't work any ideas?
const pages = []
const result = []
const limit = 10;
console.log(result.length)
for (let i = 0; i < result.length; i++) {
if(limit >= result.length){
let reactionhistry = new Discord.MessageEmbed()
.setDescription(result)
pages.push(reactionhistry)
paginationEmbed(message, pages)
}
}

trying to make a redeem command for my discord bot. I want it to make the const not useable anymore

I want to make once the code is redeemed it not be able to be used
const codes = ['5345345345345345','23123123123','312312312321q3']
for (var i = 0; i < codes.length; i++) {
if (message.content.includes(`redeem ${codes[i]}`)) {
message.channel.send("YES IT WORKED")
break;
}
}
You can essentially use Array.prototype.splice() to remove elements from the array therefore modifying it, so i would do something like this
const codes = ['5345345345345345','23123123123','312312312321q3']
for (var i = 0; i < codes.length; i++) {
if (message.content.includes(`redeem ${codes[i]}`)) {
// finding index of the code
const index = codes.indexOf(codes[i]);
//splicing from array
codes.splice(index, 1) // splice(index of element, number of elements to delete)
message.channel.send("YES IT WORKED")
break;
}
}

React for loop create infinite call

I'm currently encountering a problem when i'm calling a for loop in a functional/class component in React. For exemple if I want to create a simple function to render multiple td tr in a table React is going to infinite call the function.
class ReserveView extends Component {
createTable() {
const table = []
for (let i = 0; i < 3; i + 1) {
const children = []
for (let j = 0; j < 5; j + 1) {
children.push(<td>{`Column ${j + 1}`}</td>)
}
table.push(<tr>{children}</tr>)
}
return table
}
render() {
return (
<div>
<table>
{this.createTable()}
</table>
</div>
)
}
If i console.log(j) the console will output
this
I'm using React for a year now and it's the first time I'm having this issue. Thanks a lot for your help
Oh yeah, your problem lies in the fact that you never increase the i and j loop variant.
you need to do i++ and j++ instead of j + 1 :)
Change your +1s to ++
for (let i = 0; i < 3; i++) {
const children = []
for (let j = 0; j < 5; j++) {
children.push(<td>{`Column ${j + 1}`}</td>)
}
table.push(<tr>{children}</tr>)
}
return table
The correct answer has been posted above. Just a note that you may try ES6 map() function. It would be very useful when you are coding with React.
createTable2() {
const rows = Array(3).fill(null);
const columns = Array(5).fill(null);
return rows.map((item, ridx) => (
<tr>
{columns.map((item, cidx) => (
<td>{`Row ${ridx + 1} - Column ${cidx + 1}`}</td>
))}
</tr>
));
}
Check out the demo here: https://codesandbox.io/s/table-demo-fgd9i

es6 for loop not looping

I am trying to get a simple ES6 for-loop working but cant figure out why its not running.
I've copied an example from developer.mozilla docs and I've also tried it with the eslinter version which is below:
I have also added a let i = 0; above. All it renders/logs is i = 0 and wont increment.
the eslint version is here: eslint site
for (i = 0; i < 10; i += 1) {
console.log('i', i);
return <p>component {i}</p>;
}
Edit: ok got the values coming back in the log as i=0, i=1, etc... but to get them into a component each? i tried the push into array and mapping through to get the components out but i get no error and nothing appearing, even if i try just getting a value out.
const nbPageArray = [];
let i = 0;
for (i = 0; i < nbPages; i += 1) {
console.log('i', i);
nbPageArray.push(<p>component {i}</p>);
}
console.log('array', nbPageArray);
nbPageArray.map(a => <p>{a.type}</p>);
}
final working version:
const nbPageArray = [];
for (let i = 0; i < nbPages; i += 1) {
nbPageArray.push({ page: i + 1 });
}
return nbPageArray.map(a =>
<li className="page-item"><a className="page-link">{a.page}</a></li>,
);
Main issue is i += 10;
That should be 1 += 1;
And You should return array of elements :
var p_tags = [];
for (i = 0; i < 10; i += 1) {
console.log('i', i);
p_tags.push(<p>component {i}</p>);
}
return p_tags;
Edited question's answer :
First Error:
const nbPageArray = []; should be var nbPageArray = [];
Second You are not returning the array so change your code to this
return nbPageArray.map(a => <p>{a.type}</p>);
If you return from your for loop, you will exit the current function, you are also incrementing i by 10 each trip so you will exit the loop after one round either way.
If you are trying to print a string with the value of i ten times you could try using template string like so:
for (i = 0; i < 10; i += 1) {
console.log('i', i);
console.log(`<p>component ${i}</p>`);
}
you are returning from the loop and also incrementing by 10. The loop will execute only once.
As said in the comments, the return inside the for loop is going to exit from the function at the first iteration.
You can do something like this instead:
const result = Array(10).fill().map((_, i) =>
<p>component {i}</p>
);
Or
const result = [...Array(10)].map((_, i) =>
<p>component {i}</p>
);

Resources