React with easy-peasy - reactjs

My route:
const id = req.params.id
const event = await events.findByPk(id, {
include: [clubs]
})
return res.json(event)
})
Result in Postman:
{
"id": 12,
"title": "Title",
"description": "Short description",
"clubId": 1,
"club": {
"id": 1,
"clubname": "My Club"
}
}
On my page I'm getting data using useEffect calling my action and updating "currentEvent" in state:
const currentEvent = useStoreState(state => state.currentEvent)
const fetchEventById = useStoreActions(actions => actions.fetchEventById)
const { id } = useParams()
useEffect(() => {
fetchEventById(id)
}, [])
Destructuring data:
const { title, description, club } = currentEvent
This is working well, and state is updated:
<h1>{title}</h1>
This is not working at all. State will not be updated and the Console says "Cannot read properties of undefined (reading 'clubname')":
<h1>{title}</h1>
<h2>{club.clubname}</h2>
Any ideas?

I think you should wait data fetched correctly and then you can see your updated.
Please refactore your code by using ? like this club?.clubname

Related

What steps should I take to investigate comment is not displaying immediately with meteorjs and reactjs

I have comment section where people can talk and currently when I post comment, I have to refresh a page to see my new comment.
Iā€™m really new to meteor so Iā€™d like to know what steps should I take to invest this behavior.
client-side
const CommentList = ({ cardId }) => {
const query = useMemo(
() => ({
$or: [
{ commentType: COMMENT_TYPE.smsComment },
{
$and: [
{ commentType: COMMENT_TYPE.cardComment },
{ createdAt: { $gte: System.getChatCommentsDate() } }
]
}
]
}),
[]
);
const isCommentsLoading = useSubscribe("card.comments", cardId);
const comments = useFind(
() =>
CardComments.find(
{
cardId,
...query
},
{ sort: { createdAt: 1 } }
),
[cardId, isCommentsLoading()]
);
const memoizedComments = useMemo(
() =>
comments?.map(({ _id, userId }) => <Comment key={_id} commentId={_id} />),
[comments, reporterId]
);
return <>{isCommentsLoading() ? <LoadingIcon /> : memoizedComments}</>;
};
serverside/publication
Meteor.publish(
'card.comments',
(
cardId,
query = {
commentType: {$in: [COMMENT_TYPE.cardComment, COMMENT_TYPE.smsComment]},
},
) => {
check(cardId, String);
check(query, Object);
return CardComments.find(
{
cardId,
...query,
},
{
sort: {createdAt: -1},
},
);
},
);
So far, I read an article about useSubscribe and useFind
https://blog.meteor.com/how-to-use-meteor-with-react-hooks-7e1791daabab
I made sure after I hit a submit comment button, comment is store in a database.
Also I looked at the meteor extension on chrome and Subscriptions tab. I see card.comments is subscribed.
in Minimongo tab, I only see three card_comments documents existing. but I have 8 comments displayed on the screen.
After I submitted the comment, I see nothing happens in DDP tab.
What do you expect happening here? or what else can I do?

React State Updation Issue

My component's state is as below:
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {},
});
teamMembersOptions are being mapped from the redux state teamMembersList as below:
const teamMembersList = useSelector(state => state.get_all_team_members.team)
useEffect(() => {
if (teamMembersList)
mapTeamMembers();
}, [teamMembersList])
const mapTeamMembers = () => {
const teamMembers = [];
teamMembersList.map(member => {
const memberObject = {
'value': member.id,
'label': member.first_name.charAt(0).toUpperCase() + member.first_name.slice(1) + ' ' + member.last_name.charAt(0).toUpperCase() + member.last_name.slice(1)
}
if (member.is_leader == 1) {
memberObject.label = memberObject.label + ' (owner)'
setState({
...state,
selectedTeamMember: memberObject
})
}
teamMembers.push(memberObject)
})
setState({
...state,
teamMembersOptions: teamMembers
})
}
The state variables of selectedTeamMember and teamMemberOptions are not updating, it keeps consoling empty state. Whenever I console the local array of teamMembers inside mapTeamMembers function, it logs all the values successfully teamMembersList from Redux
also logs successfully that means teamMembersList and teamMembers are not empty. But the state is not updating. Why the setState statement inside mapTeamMembers function is not updating the state?
There are a number of things going on here and lot of them cause renders to trigger more renders which is why you are getting unexpected output.
I have add useMemo() and useCallback() around the data and calculation method respectively, and added their return values to the dependency array for useEffect(). This is to avoid the useEffect dependencies change on every render.
Calling setState() within the .map() function doesn't feel like the right choice either as each time it is called a render might occur, even though you are halfway through the mapping operation. Instead I suggest, and opted for, using .reduce() on the array and returning that result which can then be used to update the state within the useEffect hook.
Have a look at the working code below and a sample output given the defined input from teamMembersList. Note: this doesn't use Redux in the example given that it more setup to prove the concept.
import { useCallback, useEffect, useMemo, useState } from "react";
export default function App() {
const [state, setState] = useState({
teamMembersOptions: [],
selectedTeamMember: {}
});
const teamMembersList = useMemo(
() => [
{ id: 1, first_name: "John", last_name: "Smith", is_leader: 0 },
{ id: 2, first_name: "Maggie", last_name: "Simpson", is_leader: 1 }
],
[]
);
const mapTeamMembers = useCallback(
() =>
teamMembersList.reduce(
(acc, member) => {
const memberObject = {
value: member.id,
label:
member.first_name.charAt(0).toUpperCase() +
member.first_name.slice(1) +
" " +
member.last_name.charAt(0).toUpperCase() +
member.last_name.slice(1)
};
if (member.is_leader === 1) {
memberObject.label = memberObject.label + " (owner)";
acc.leader = memberObject;
}
acc.teamMembers.push(memberObject);
return acc;
},
{
teamMembers: [],
leader: ""
}
),
[teamMembersList]
);
useEffect(() => {
if (teamMembersList) {
const members = mapTeamMembers();
setState({
selectedTeamMember: members.leader,
teamMembersOptions: members.teamMembers
});
}
}, [teamMembersList, mapTeamMembers, setState]);
return (
<div>
<pre>
<code>{JSON.stringify(state, null, 4)}</code>
</pre>
</div>
);
}
The above will render out:
{
"selectedTeamMember": {
"value": 2,
"label": "Maggie Simpson (owner)"
},
"teamMembersOptions": [
{
"value": 1,
"label": "John Smith"
},
{
"value": 2,
"label": "Maggie Simpson (owner)"
}
]
}
I'd consider splitting the state object into individual state items but that's really up to you and how you want to handle the data.

Nested array with React and Firestore - How to display?

I have a nested array within the individual items in a collection.
{
"id": "RpFRcKLIgELlBLgIOJM4",
"Category": "",
"Method": "",
"User": "rWFZhAKk9eOSIIFoP0DqqvrC6WJ3",
"Foods": [
{
"Weight": 1.065,
"label": "Milk - Long Life (1 Litre) (1.065)",
"value": "Milk-LongLife(1Litre)"
},
{
"label": "Blueberries (0.125)",
"value": "Blueberries",
"Weight": 0.125
}
],
"Name": "456",
"Serves": ""
}
{
"id": "WQ6KBLevFsCdV73j4KU4",
"Category": "",
"Name": "123",
"Foods": [
{
"value": "Wine-White",
"label": "Wine - White"
},
{
"value": "Milk-LongLife(1Litre)",
"label": "Milk - Long Life (1 Litre)"
}
],
"Serves": "",
"User": "rWFZhAKk9eOSIIFoP0DqqvrC6WJ3",
"Method": ""
}
const useItemsMeals = () => {
const user = firebase.auth().currentUser;
const user1 = user.uid;
const [items, setItems] = useState([]); //useState() hook, sets initial state to an empty array
useEffect(() => {
const unsubscribe = firebase
.firestore()
.collection("meals")
.where("User", "==", user1)
.orderBy("Category", "asc")
.onSnapshot(snapshot => {
const listItemsMeals = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
setItems(listItemsMeals);
console.log(listItemsMeals);
});
return () => unsubscribe();
}, []);
return items;
};
I am having a tough time trying to display items from the 'Foods' array, am currently using for my return:
const listItemMeals = useItemsMeals();
{listItemMeals.map(item => (
<TableRow hover key={item.id} id={item.id}>
<TableCell>{item.Category}</TableCell>
<TableCell>{item.Name}</TableCell>
<TableCell>{item.Foods}</TableCell>
When doing this it tells me:
Error: Objects are not valid as a React child (found: object with keys {label, value}). If you meant to render a collection of children, use an array instead.
I think I need to map this nested array again somehow - but for the life of me - cannot figure it out!
You're almost there.
Your useItemsMeals functions loads the data from Firestore, and sets it correctly into the items variable in the state to render it. But then you use const listItemMeals = useItemsMeals() in your rendering code, which messes things up.
You should not try to return any value from useItemsMeals, and instead solely rely on the items variable from the state to pass the information between the database and the rendered.
So:
// return items; šŸ‘ˆ remove this
---
// const listItemMeals = useItemsMeals(); šŸ‘ˆ remove this
---
{items.map(item => ( // šŸ‘ˆ read items from the state instead
You need to loop over the Foods array again. Like this
const listItemMeals = useItemsMeals();
{listItemMeals.map(item => (
<TableRow hover key={item.id} id={item.id}>
<TableCell>{item.Category}</TableCell>
<TableCell>{item.Name}</TableCell>
{
item.Foods.map(food=>(
<div> //this can div or a new row tag
<TableCell>{food.weight}</TableCell>
<TableCell>{food.label}</TableCell>
<TableCell>{food.value}</TableCell>
</div>))
}

Update data from array with multiple objects using Axios PUT request

I need to update data in an array that has multiple objects where a user will input a new balance that will update the old balance state. The array consists of a company name with an array called details, and that array holds objects containing employee information(name, balance, notes), for this question I am just using notes to simplify things. I am using Axios PUT to access the id of the nested object, I get the id from a Link that is passed via useParams hook.
My issue is in the Axios PUT request. Before I had a schema that was just a data object (no arrays were in it) and the PUT req was working fine. Then I needed to change the schema to an array with multiple objects and now I cannot seem to update the data. I am able to target the data through the console log but when I take that code from the console and apply it, the state still doesn't change. Even in Postman, the only way for me to successfully update is to get the Shema from a GET request and paste that schema in the PUT request and change some data in it, then I hit send and it updates, but to get it to update again I need to hit send twice (this shouldn't be, no? ).
I am able to access the data and render it in other components by mapping it twice as shown below:
setBalance(res.data.data.details.map((r) => r.balance));
My question: How can I edit the below code to update the state correctly?
setNotes([...details, res.data.data.details.map((r) => r.notes )]);
However, I am really struggling with how to do this in the Axios PUT request.
Here is my code:
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { useParams } from "react-router-dom";
import axios from "axios";
const AddForm = () => {
const [newBalance, setNewBalance] = useState("");
const [details, setDetails] = useState([]);
const [notes, setNotes] = useState("");
const [total, setTotal] = useState("");
const { id } = useParams();
const history = useHistory();
//update balance
const updateBal = () => {
// function to calculate balance
};
const updateBalHandler = (e) => {
e.preventDefault();
axios({
method: "PUT",
url: `http://localhost:5000/update-snapshot-test/${id}`,
data: {
balance: total
notes: notes
},
}).then((res) => {
history.push(`/success/` + id);
setNotes([...details, res.data.data.details.map((r) => r.notes )]); //this code isolates the notes state but does not update it
});
};
return (
<form
action="/update-snapshot/:id"
method="post"
onSubmit={updateBalHandler}
>
<Input
setInputValue={setNewBalance}
inputValue={newBalance}
inputType={"number"}
/>
<Input
setInputValue={setTotal}
inputValue={total}
inputType={"number"}
/>
<TextArea
setInputValue={setNotes}
inputValue={notes}
inputType={"text"}
/>
<Button onClick={() => { updateBal(); }} >
Update
</Button>
<Button type="submit">
Save
</Button>
</form>
);
};
export default AddForm;
Here is my data structure from Mongo DB
{
"message": "Post found",
"data": {
"company": "Riteaid",
"_id": "1",
"details": [
{
"employee": "jane doe",
"balance": "3",
"notes": "some notes",
"_id": "2"
},
{
"employee": "john doe",
"balance": "1",
"notes": "some more notes",
"_id": "3"
}
],
}
}
You have the id, so you have to search for the relevant object, update it and pass it to the setNotes() setter.
let localNotes = res.data.data.details.map((responseDetail) => {
if (detail._id === id){
let newNotes = [...responseDetail.notes, ...details];
return {
...responseDetail,
notes: newNotes
};
}
return responseDetail;
});
if (localNotes.length){
setNotes(localNotes);
}
Does this solve your problem?
The answer was in the backend, the front end was fine, the code did not need any of the additions, it should just be:
const addBalHandler = (e) => {
e.preventDefault();
axios({
method: "PUT",
url: `http://localhost:5000/endpoint${id}`,
data: {
balance: total,
notes: notes,
date: date,
},
}).then((res) => {
history.push(`/success/` + id);
console.log(res.data);
});
};

Using JSON returned from an API to populate a variable used by a React-Table table component

I'm trying to write this React component that connects to an API that returns JSON.
The API returns JSON results that look like this small example:
JSON:
{
"id": 22,
"gameTitle": "The Haunted Plains II",
"startDate": "2020-03-31T12:49:50.009",
"endDate": "2020-04-04T04:00:00",
"description": "A simple bitmap style RPG",
"gameUrl": "https://yourgames.org/1/55/3",
"isOpen": true,
"gameFaqId": 25,
"gameTypeId": 3,
"gameCharClasses": ["Bard", "Theif", "Warrior", "Wizard", "Cleric"]
},
{
"id": 25,
"gameTitle": "Downhill Mountain Biking Pro",
"startDate": "2020-02-12T11:22:30.011",
"endDate": "2020-05-02T03:11:00",
"description": "A side-scrolling, downhill mountaining biking game",
"gameUrl": "https://yourgames.org/3/43/6",
"isOpen": true,
"gameFaqId": 11,
"gameTypeId": 6,
"gameCharClasses": ["Beginner", "Pro", "Super Star"]
}
I want to put the data into the 'gameListing' variable that have defined as 'const gameListing'.
Then I have a function called makeData that is called by the main app which is using a React library called 'react-table'.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'https://localhost:44376/api/projects',
);
setData(result.data);
};
fetchData();
}, []);
const range = len => {
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(i);
}
return arr;
};
const gameListing = data.map(g => {
return {
id: g.id,
gameTitle: g.gameTitle,
startDate: g.startDate,
endDate: g.endDate,
description: g.description,
gameUrl: g.gameUrl,
isOpen: g.isOpen,
gameFaqId: g.gameFaqId,
gameCharClasses: g.gameCharClasses
};
});
export default function makeData(lens = [2]) {
const makeDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...gameListing(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}
return makeDataLevel()
}
The problem is, after hours of debugging, I can't get it to work.
My latest issue is that it's not displaying any data.
Here is a Code Sandbox: https://codesandbox.io/s/trusting-booth-b7wxg
I see one problem is youre using .map wrong
you have to pass in a parameter and that parameter is basically like a placeholder to use that has the data within it
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
for example:
const gameListing = data.map((elem) => {
return {
id: elem.id,
gameTitle: elem.gameTitle,
startDate: elem.startDate,
endDate: elem.endDate,
description: elem.description,
gameUrl: elem.gameUrl,
isOpen: elem.isOpen,
gameFaqId: elem.gameFaqId,
gameCharClasses: elem.gameCharClasses
}
})
Does that help or work?

Resources