I'm a beginner in web development, so I'm trying to do a simple 'GET' with the hook "useQuery" of Hasura, and I can't access to my data. However, my query has been tested on the Hasura console, and it works. I have several array with some datas on the json side.
So I don't understand why when I'm trying to get data in my React project, it doesn't works and datas are set on "undefined".
Here is my code :
const GET_DATA_FOR_ACHIEVEMENTS = gql`
query getDataForAchievments{
UserAchievements {
additionalInfo
created_at
label
points
step
userEmail
}
}`;
type AchievementsResult = {
created_at: string;
points: number;
label: string;
userEmail: string;
step: string;
additionalInfo: string;
};
export const Statistics = () => {
const { user, isLoading } = useAuth0();
const {data, error, loading} = useQuery(GET_DATA_FOR_ACHIEVEMENTS);
let filteredDatas = data.UserAchievements;
console.log(filteredDatas[0].step);
console.log("*************")
Someone know why ?
Thanks for you future helps
Initially data will be undefined. do this way.
export const Statistics = () => {
const { user, isLoading } = useAuth0();
const {data, error, loading} = useQuery(GET_DATA_FOR_ACHIEVEMENTS);
if(loading){
return 'Loading...';
}
if(error){
return 'error :(';
}
let filteredDatas = data.UserAchievements;
console.log(filteredDatas[0].step);
console.log("*************")
Related
What I need to do is to be able to log in with GIS, and then fetch an URL that would end with the {user.email} we just got from decoding the JWT.
Here is my code :
interface userI {
name: string | null;
iat?: number;
iss?: string;
picture?: string;
email?: string;
}
interface bookingI {
id: number;
bureau: string;
aile: string;
office: string;
office_id: string;
cote: string;
time: Date;
etage: string;
direction: string;
espace: string;
}
const [ user, setUser] = useState<userI>({name: null});
function handleCallbackResponse(response: any) {
console.log("Encoded JWT ID token: " + response.credential);
var userObject = jwt_decode(response.credential);
console.log(userObject);
localStorage.setItem('user', JSON.stringify(userObject))
setUser(userObject as userI);
document.getElementById("signInDiv")!.hidden = true;
}
useEffect(() => {
/* global google */
//#ts-ignore
google.accounts.id.initialize({
client_id: "myId",
callback: handleCallbackResponse
});
//#ts-ignore
google.accounts.id.renderButton(
document.getElementById("signInDiv"),
{ theme: "outline", size: "large", shape: "pill"}
);
},[]);
const [booking, setBooking] = useState<bookingI>();
const apiUrl = "apiUrl"
useEffect(() => {
const api = async () => {
const data = await fetch(`${apiUrl}/${user.email}`, {
method: "GET"
});
const jsonData = await data.json();
console.log("jsonData : ")
console.log(jsonData)
setBooking(jsonData.data);
};
api();
},[]);
What I have been able to do so far : Log in with GIS, decoding JWT and display {user.email} it in return, fetch my API NOT dynamically ("url/myemail").
What I did not manage to do : Be able to fetch (`url/${user.email}`) the moment login with GIS was successful (and not before), stay signed in even after refreshing (maybe it's the problem I need to fix).
Pretty new to Typescript, thank you for your patience and consideration.
Solved :
const userEmail = user.email
const fullUrl = `${apiUrl}/${userEmail}`
useEffect(() => {
const api = async () => {
//console.log(fullUrl)
const data = await fetch(`${fullUrl}`, {
method: "GET"
});
const jsonData = await data.json();
//console.log("jsonData : ")
//console.log(jsonData)
console.log("Extractable data : ")
console.log(jsonData.data)
setBooking(jsonData.data);
};
if (userEmail !== undefined){
api();
}
},[fullUrl, userEmail]);
I still need to stay signed in even after refreshing but my main problem is solved
My code works, and the console.log is showing the object, and if i go to my firebase console and change the data then it is updated in realtime.
However when initially direcred by my router to the PlaylistDetails.vue it is taking the empty fields and displaying them whilst my program talks to firebase, when data is returned the console prints but my fields are still blank.
im assuming i need to get an async await function in there somewhere, or v:bind
export default {
props: ["id"],
setup(props) {
const db = getFirestore();
const docRef = doc(db, "playlists", props.id);
const playlist = { id: "", title: ""};
const unsub = onSnapshot(docRef, (doc) => {
playlist.id = doc.id;
playlist.title = doc.data().title;
console.log(playlist);
});
watchEffect((onInvalidate) => {
onInvalidate(() => unsub());
});
return { playlist };
},
};
Im new to using typescript with react. I have an application where I call an api and set the response to a state. I have created a generic type for api calls as follow.
const responseBody = <T>(response: AxiosResponse<T>) => response.data;
const restApiCalls = {
get: <T>(url: string) => axios.get<T>(url).then(responseBody),
post: <T>(url: string, body: {}) =>
axios.post<T>(url, body).then(responseBody),
put: <T>(url: string, body: {}) => axios.put<T>(url, body).then(responseBody),
};
const users = {
getUsers: () =>
restApiCalls.get<Users[]>("https://jsonplaceholder.typicode.com/users"),
};
const apis = {
users,
};
export default apis;
The getUser() function calls the get request and returns a list of Users
The following is the User interface
export interface Users {
id: boolean;
name: string;
username: string;
email: string;
address: Address;
phone: string;
website: string;
company: Company;
}
interface Address {
street: string;
suite: string;
city: string;
zipcode: string;
geo: Geo;
}
interface Geo {
lat: string;
lng: string;
}
interface Company {
name: string;
catchPhrase: string;
bs: string;
}
When calling the api, the api returns the data successfully and I assigned the returned data to the state using setUsermethod.
Following is the state.
const [user, setUser] = useState<Users[]>();
I assigned the fetched data to state as follow.
useEffect(() => {
const fetchData = async () => {
const res = await apis.users.getUsers();
setUser(res);
};
fetchData();
}, []);
when console the user state, the data is is there and it is logged successfully. But I want to check the length of the user state in a if condition. If I check the length, it show the following error.
Object is possibly 'undefined'.ts(2532)
This is the code I used to check the length
const someFunction= () => {
if (user?.length > 1) {
for (let index = 0; index < user?.length; index++) {
console.log(user[index])
}
}
};
But I if set the state type to any instead of User[], it works. WHat might be the issue?
The expressions with users are all capable of resolving to undefined, which cannot be compared to a number and cannot be indexed. For example user?.length could be undefined (if user is undefined); same with user[index]
You need to handle the undefined case. For example:
const someFunction= () => {
if(!user) { return; }
if (user.length > 1) {
for (let index = 0; index < user.length; index++) {
console.log(user[index])
}
}
};
My Code looks like this:
interface MutationProps{
username: any,
Mutation: any
}
const UseCustomMutation: React.FC<MutationProps> = (MutationProps: MutationProps) => {
const [myFunc, {data, error}] = useMutation(MutationProps.Mutation);
useEffect(() => {
myFunc({variables:{username: MutationProps.username}})
console.log(JSON.stringify(data))
console.log(JSON.stringify(error, null , 2))
}, [])
return data
}
export const DisplayUser = () => {
const GET_USER = gql`
mutation GetUser($username: String!){
getUser(username: $username) {
pfp
username
password
age
CurrentLive
ismod
description
fullname
}
}
`
const {username} : {username: any} = useParams()
const MyData = UseCustomMutation(username, GET_USER)
console.log(JSON.stringify(MyData))
But I get this error back: ×
Argument of undefined passed to parser was not a valid GraphQL DocumentNode. You may need to use >'graphql-tag' or another method to convert your operation into a document
How about your code looks like this:
interface MutationProps {
username: string;
Mutation: any;
}
const UseCustomMutation: React.FC<MutationProps> = ({ username, Mutation }) => {
const [functionForDoingAction, { data, loading, error }] = useMutation(
Mutation,
{
variables: {
username,
},
}
);
useEffect(() => {
// fn trigger for change data
functionForDoingAction({
variables: {
username: "string_value",
},
});
console.log(JSON.stringify(data));
console.log(JSON.stringify(error, null, 2));
}, []);
if (loading) return "loading...";
if (error) return `Submission error! ${error.message}`;
return data;
};
export const DisplayUser = () => {
const GET_USER = gql`
mutation GetUser($username: String!) {
getUser(username: $username) {
pfp
username
password
age
CurrentLive
ismod
description
fullname
}
}
`;
const { username }: { username: string } = useParams();
const MyData = UseCustomMutation(username, GET_USER);
console.log(JSON.stringify(MyData));
};
you can pass an argument directly to the useMutation hook which they provide as an Options parameter. Or is the direct trigger function from the hook you get.
I am unsure of how to change/update the data in my database through react.
My database:
const Package = new mongoose.Schema({
packageID = {type: String},
packageStatus = {type: String, enum: [packed, delivered, received], default: 'packed' },
})
how do I refer to packageStatus and their enum values in react/class component? How should I call them?
The default value is 'packed', I want to change it to 'delivered' when a button is clicked (no text fields involved).
class PackageStatus extends React.Component {
constructor(){
super()
this.state = {
packageStatus: 'packed'
}
this.updateStatus = this.updateStatus.bind(this);
}
updateStatus(){
this.setState =({
packageStatus: 'delivered'
}
)
render(){
return (
<div?
<button onClick={()=> packageStatus(this)}>Update Status</button>
</div>
)
}
}
export default PackageStatus
The code above changes the text displayed but not the status in the database, so how do I change the data in the database?
Next, I would want to display text depending on what the status in the database is. I'm not sure how to link isDelivered to the condition of the database.
For example
class Status extends Component {
constructor(props) {
super(props);
this.state = {
isDelivered: true
};
}
render() {
let { isDelivered } = this.state;
let status;
if (isDelivered) {
status = <h1>Delivered<h1>
} else {
status = <h1>Packing in progress<h1>
}
return (
<div>
{status}
</div>
);
}
}
export default Status;
Any help will be greatly appreciated! Thank you for your time
Well interfacing, a frontend framework like REACT with a database, an easier approach would be create apiEndpoints of which you would use make fetch or axios to make httpRequests which communicates to these endpoints, in turn communicate with the database to give you your desired response. A solution approach to your problem is as follows:
Create the schema using mongoose in node
const mongoose = require('mongoose')
const { Schema } = mongoose
const PackageSchema = new Schema({
packageID: {
type: String,
},
packageStatus: {
type: String,
enum: ["packed", "delivered", "received"],
default: 'packed'
}
})
module.exports = mongoose.model('package',PackageSchema)
Create the apiEndpoints or routes to interface this schema with FrontEnd(React) and Backend(eg; mongodb)
const express = require('express');
const router = express.Router();
require('dotenv').config()
const package = require('../model/packageModel');
router.get('/allpackages', async(req, res) => {
try{
const getAllPackages = await package.find();
res.json(getAllPackages);
}catch(err){
res.json({
message: err
})
}
})
router.post('/addPackage',async(req, res) => {
const pack = new package({
packageID: req.body.packageID,
packageStatus: req.body.packageStatus
})
try{
const savedPost = await pack.save();
res.json(savedPost);
}catch(err){
res.json({
message: err
})
}
})
router.patch('/updatePackageStatus', async (req, res) => {
try {
const updatePackageStatus = await package.updateOne(
{ _id: req.body.packageID },
{
$set: {
packageStatus: req.body.packageStatus
}
}
)
res.json(updatePackageStatus)
}catch (err) {
res.json({
message: err
})
}
})
module.exports = router;
Use POSTMAN or any other of choice to test endpoints with schema, and database, to see if you get the desired results. After testing out the above, with POSTMAN, all desired operations work as expected, and you should have no problem, interfacing it with any Frontend Framework(Angular, React, Vue) now.
GET http://localhost:3000/package/allpackages
POST http://localhost:3000/package/addPackage
PATCH http://localhost:3000/package/updatePackageStatus
sample screenshot shown below
fetch api Endpoints via postman