Value of props is undefined when accessed inside a function - reactjs

I have a function which update and add new record to my database. I have passed props called matterId from parent to child component but if I do console log inside the functions, it shows undefined instead.
import React, { useState, useEffect } from 'react';
import { Table, Button, Modal, Form } from 'react-bootstrap';
export default function TimeEntry(props){
const { matterId, timeEntriesData } = props;
console.log(`matterId: ${matterId}`)
const [timeEntries, setTimeEntries] = useState([]);
const addTimeEntry = (e, matterId) => {
console.log(`matterId: ${matterId}`)
e.preventDefault();
fetch(`http://localhost:4000/matters/628607f1c8a4009f2fd4801e/timeEntry`, {
method: 'PUT',
headers: {
Authorization: `Bearer ${ localStorage.getItem('token') }`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
description: entryDescription
})
})
.then(res => res.json())
.then(data => {
if (data === true) {
// fetchData();
alert("New time entry successfully aded.");
closeEdit();
} else {
alert("Something went wrong.");
closeEdit();
}
});
};
};
console.log shows this: matterId: undefined

You are declaring the variable again in the function signature.
Change it something like this
const addTimeEntry = (e) => {
console.log(`matterId: ${matterId}`)
....
}

const { matterId, timeEntriesData } = props;
// This matterId is from props.
console.log(`matterId: ${matterId}`);
const [timeEntries, setTimeEntries] = useState([]);
const addTimeEntry = (e, matterId) => {
// This matterId is from function addTimeEntry
console.log(`functionMatterId: ${matterId}`);
};
// Call function like this
addTimeEntry(e, "id"); // expected console >> functionMatterId: id

Related

Call useSWR by previous useSWR data.map then got Error(useSWR to get google calendar event)

I write a hook named useGoogleCalendarEvents, Try to get users google calendar event,below is my code.
import { Schedule, User } from '../../types/commons.type';
import { useLocalStorage } from 'usehooks-ts';
import useSWR from 'swr';
import { FetchCalendarList } from '../../types/googleCalendarAPIResponse.type';
import { currentUTCMonthString } from '../../utils/DateUtils';
const baseURL = 'https://www.googleapis.com/calendar/v3';
const fetcher = ([path, method, body = {}, accessToken = '']: [string, string, object, string]) => {
const headers = {
'Content-Type': ['POST', 'PUT', 'PATCH'].includes(method) ? 'application/json' : '',
Authorization: `Bearer ${accessToken}`,
};
const fetchOptions = {
method,
headers,
body: method === 'GET' ? undefined : JSON.stringify(body),
};
const apiURL = `${baseURL}${path}`;
return fetch(apiURL, fetchOptions).then((r) => r.json());
};
export const useGoogleCalendarEvents = () => {
const [user, setUser] = useLocalStorage<User | undefined>('user', undefined);
const events: Array<string> = [];
if (user?.googleAccessToken) {
// get user calendar list
const { data: GoogleCalendarListResult } = useSWR<FetchCalendarList>(
['/users/me/calendarList', 'GET', {}, user?.googleAccessToken],
fetcher,
);
const { startString, endString } = currentUTCMonthString();
const parameters = `timeMin=${startString}&timeMax=${endString}`;
// map loop to get event by calendar id
GoogleCalendarListResult?.items?.map((calendar) => {
const { data: GoogleCalendarEventResult } = useSWR(
[`/calendars/${calendar.id}/events?${parameters}`],
fetcher,
);
});
}
return { events };
};
the code not yet finish but i got the error
"React has detected a change in the order of Hooks called by MySettingPage2."
I modify the code
GoogleCalendarListResult?.items?.map((calendar) => {
const { data: GoogleCalendarEventResult } = useSWR(
[`/calendars/${calendar.id}/events?${parameters}`],
fetcher,
); });
to
['calendarid1', 'calendarid2'].map((calendar) => {
const { data: GoogleCalendarEventResult } = useSWR(
[`/calendars/${calendar.id}/events?${parameters}`],
fetcher,
);
});
It is work, but not flexble. I want to get calendar id list first, then get envets by calendar id
Is anybody known why cause this error? Thank for any reply

json response from mock server not printing but is in the console

I am trying to learn react, and I am making a successful API call, but it only prints in the console. I found examples but many of them recommended to use setData(json) but I am not able to use it because the file is a list of export async function which was also recommended.
export async function GetHellWorld() {
return fetch(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => {
console.log(json)
})
.catch(error => (console.log(error)))
}
and the component
function Test(thisArg, argArray) {
const result = GetHellWorld.apply()
return (
<div className="App">
{JSON.stringify(result)}
</div>
);
}
export default Test;
In the console I see "Hello World" but in the browser is get just {}.
Two questions:
How can I bind the JSON response to an object so I can do something like result.name.
Is this the correct was to call the await function? const result = GetHellWorld.apply()
---- update ----
I decided to try axios because I want to make multiple calls in one file.
const axios = require('axios');
export class AppService {
public async GetHelloWorld(): Promise<any> {
const response = await axios.get(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).catch(() => console.log("Issue in GetHelloWorld"))
return response.data
}
}
component
import React from 'react';
import {AppService} from "../services/app.service";
function Movies() {
const api = new AppService()
const hello = async () => {
const response = await api.GetHelloWorld();
console.log("The response: " + response)
}
return (
<div className="App">
{JSON.stringify(hello)}
</div>
);
}
note I had to add typescript support.
For whatever reason I get
Module not found: Error: Can't resolve '../services/app.service' in '/Users/miketye/programming/test-react/src/components'
While the other answer about using a custom hook can work, I would not recommend it while you're still leaning React.
Look up how to use the "useEffect" hook, that's generally how you want to do any sort of loading logic in React.
First off, you need to fix your async function so it actually returns a value:
// style/convention note, but non-component functions should not start with a capital letter
export async function getHelloWorld() {
return fetch(`http://localhost:8080/api`, {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => {
return json // will cause this function to return a Promise of type "string", since we're in an async function
})
// better to just let the error get thrown here, for testing
}
Then use it like this:
function Test(thisArg, argArray) {
[fetchResult, setFetchResult] = useState(undefined) // look up useState. State is how you have values that change over time in a resct component
useEffect(() => {
async function fetchData() {
const data = await getHelloWorld()
setFetchResult(data)
}
fetchData()
}, [])
// look up useEffect. Since the second argument (the "dependency array") is empty, useEffect will fire only once, after the component loads
return (
<div className="App">
{result ? JSON.stringify(result) : "no result yet"}
</div>
);
}
export default Test;
You can use a custom hook for this purpose:
import { useState } from "react";
const useFetchData = () => {
const [data, setData] = useState(null);
const fetchData = () => {
fetch("http://localhost:8080/api", {
method: "Get",
headers: {
"Content-type": "application/json; charset=UTF-8"
}
}).then(response => response.json())
.then(json => { setData(json); })
.catch(error => { console.log(error); })
}
useEffect(() => {
fetchData();
}, []);
return { data, fetchData };
}
export default useFetchData;
And then call it in your component:
import useFetchData from "#/hooks/useFetchData";
const Test = () => {
const { data, fetchData } = useFetchData();
// CALL fetchData IF YOU WANT TO UPDATE THE CURRENT STATE
return (
<div className="App">
{data && JSON.stringify(data)}
</div>
);
}
export default Test;

Next.js - React Custom Hook throws Invalid hook call

Hi I am quite new to react and this is for a learning project.
In react under next.js want to check for the existence of a certain folder on the server. To achieve that I implemented an api twigExists.js in pages/api and a custom hook twigExistsRequest.js in the library folder:
import {useEffect, useRef} from "react";
import {webApiUrl} from "#/library/webHelpers";
export function useTwigExistsRequest({
parentDirSegment,
name,
action,
treeStateDispatch
}) {
const nameExists = useRef('not');
useEffect(() => {
if ('' !== name) {
async function fetchNameValidation() {
try {
const response = await fetch(
webApiUrl() + '/branchName',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({parentDirSegment, name})
}
);
const answer = await response.json();
if (undefined !== answer['exists']) {
nameExists.current = answer['exists'];
}
else if (undefined !== answer['err']) {
console.log(answer['err']);
}
} catch (err) {
console.log(err);
}
}
fetchNameValidation().then(() => {
nameExists.current === 'exists'
&& treeStateDispatch({
action,
name,
dirSegment: parentDirSegment
});
})
}
});
}
The following error is thrown at the useRef line, line 10:
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component.
I am using an almost identical approach to get the structure of a special folder with its subfolders and it is working fine. Working example:
import {useEffect, useRef} from "react";
import {webApiUrl} from "#/library/webHelpers";
export default function useChangeBranchRequest({
data,
setData
}) {
let postData;
const storeEffect = useRef(0);
if ('skip' !== data) {
storeEffect.current += 1;
postData = JSON.stringify(data);
}
useEffect(() => {
if (0 !== storeEffect.current) {
async function fetchData() {
try {
const response = await fetch(
webApiUrl() + '/changeBranch',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: postData
});
const json = await response.json();
setData(JSON.parse(json['tree']));
} catch (error) {
console.log(error);
}
}
fetchData()
.then(() => {
return (<></>);
});
}
}, [storeEffect.current]);
}
I can't see: What is wrong in the first example??
Edit due to question: useTwigExistsRequest is called from this file:
import {useTwigExistsRequest} from "#/library/twigExistsRequest";
export default function twigExistsHandler({
parentDirSegment,
name,
action,
treeStateDispatch
}) {
useTwigExistsRequest({
parentDirSegment,
action,
name,
treeStateDispatch
});
}
trying to avoid a direct call from:
import {ACTIONS} from "#/library/common";
import {useState} from "react";
import twigExistsHandler from "#/library/twigExistsHandler";
export default function PlgButton({dirSegment, action, text, treeStateDispatch}) {
const [info, SetInfo] = useState('');
const [parentDirSegment, SetParentDirSegment] = useState('');
// name validation, triggered by SetInfo. Returns strings 'false' or 'true':
// reset Button after execution
if (info) SetInfo('');
return (
<button
className="btn btn-secondary btn-sm new-plg-btn"
onClick={() => {
clickHandler(action);
}}
>
{text}
</button>
);
function clickHandler(action) {
let name;
switch (action) {
case ACTIONS.add:
name = window.prompt('New name:');
twigExistsHandler({
parentDirSegment: dirSegment,
name,
action,
treeStateDispatch
});
break;
case ACTIONS.dup:
name = window.prompt('Dup name:');
twigExistsHandler({
parentDirSegment: dirSegment.slice(0,dirSegment.lastIndexOf('/')),
name,
action,
treeStateDispatch
});
break;
case ACTIONS.del:
window.confirm('Irrevocably delete the whole playground?')
&& treeStateDispatch({
info: '',
dirSegment,
action
});
break;
}
}
}

useEffect hook infinite loop

I am new to react. here is my problem
import React, { useEffect, useState } from "react";
import { useJwt } from "react-jwt";
import { get_single_user_url } from "../../store/api";
import UrlCard from "../UrlCard/UrlCard";
import "./Urls.css";
function Urls() {
const [urls, setUrls] = useState([]);
const { decodedToken } = useJwt(localStorage.token);
const userId = decodedToken !== null ? decodedToken.userId : "";
useEffect(() => {
const hit = async (userId) => {
get_single_user_url(userId).then((data) => setUrls(data));
const data = await get_single_user_url(userId);
setUrls(data);
console.log(data);
};
hit(userId);
}, []);
return <div className="urls"></div>;
}
export default Urls;
so this useeffect will call a function
get_single_user_data(userId)
and it should return an array of urls from the database. But it returned this
{kind: "ObjectId",
path: "user",
reason: {},
stringValue: """",
value: "",
proto: Object}
This is the function
export const get_single_user_url = async (userId) => {
try {
const response = await axios({
method: "post",
url: "http://192.168.43.62:5000/getUrls",
data: { user: userId },
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
});
console.log(response.data);
return response.data;
} catch (error) {
console.log(error.message);
}
};
here userId is passed through the body. Now in the backend when I print the value of req.body, it gives user property with an empty string.
{ user: "" }
I have tried it without using useEffect but then it goes into an infinite loop.
Since you have an empty dependency array on your useEffect, it will only fire once. It looks like the userId is an empty string when running.
You'll want to add some logic in your hit function to only make the request if userId is not empty. Additionally, to get your effect to run when needed, you should add userId to the dependency array ([userId]).
If userId isn't needed anywhere other than this function, you might use the token instead, and parse the userId in your hit function.
const [urls, setUrls] = useState([]);
const { decodedToken } = useJwt(localStorage.token);
useEffect(() => {
const hit = async (decodedToken) => {
const userId = decodedToken !== null ? decodedToken.userId : "";
if (!userId) {
return;
}
get_single_user_url(userId).then((data) => setUrls(data));
const data = await get_single_user_url(userId);
setUrls(data);
console.log(data);
};
hit(decodedToken);
}, [decodedToken]);

How to create a custom Hooks in reactjs hooks?

I was trying to create a custom Hooks for handling input HTTP request from any component by simply calling the useCustomHooks but its getting failed and error is
Can not use keyword 'await' outside an async function
All i made is a handler that triggers http request custom component method
import { useState } from 'react';
import axios from "axios";
const useHttpReqHandler = () => {
const [result, setResult] = useState();
const apiMethod = async ({url , data , method}) => {
let options = {
method,
url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
data
};
let response = await axios(options);
const UpdatedData = await response.data;
console.log(UpdatedData)
setResult(UpdatedData);
}
return [result, apiMethod];
};
export default useHttpReqHandler;
Now i can use this hook in my code and on any event handler just call callAPI returned from the hook like this
const MyFunc = () => {
const [apiResult, apiMethod] = useHttpReqHandler();
const captchValidation = () => {
const x = result.toString();;
const y = inputValue.toString();;
if ( x === y) {
apiMethod({url: 'some url here', data: {"email": email}, method: 'post'});
alert("success")
}
else {
alert("fail")
}
}
Is is a correct approch ? as i am beginner in Reactjs
Here is a working version:
useHttpReqHandler.jsx
import { useState } from 'react';
import axios from "axios";
const useHttpReqHandler = () => {
const [apiResult, setApiResult] = useState();
const apiMethod = async ({url , data , method}) => {
let options = {
method,
url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
data
};
let response = await axios(options);
let responseOK = response && response.status === 200 && response.statusText === 'OK';
if (responseOK) {
const data = await response.data;
console.log(data)
setApiResult(data);
}
}
return [apiResult, apiMethod];
};
export default useHttpReqHandler;
What's important here:
await is called inside an async function (apiMethod)
The result is stored in a local state (apiResult)
The function returns an array [apiResult, apiMethod]
How to use it:
const [apiResult, apiMethod] = useHttpReqHandler();
apiMethod({url: 'some url here', data: {"email": email}, method: 'post'});
Render the result:
return {apiResult};
In my opinion, it is better to use .then with Axios. and try to create for each method different functions "Get/Post...", why because in the GET method you need to useEffect, but it can not be the same case in POST method. in GET method useHttpReqHandler.js
import { useEffect, useState } from "react";
import axios from "axios";
// GET DATA
const useHttpReqHandler = (url) => {
const [httpData, setHttpData] = useState();
useEffect(() => {
axios
.get(url)
.then((axiosData) => {
// Axios DATA object
setHttpData(axiosData.data);
// you can check what is in the object by console.log(axiosData);
// also you can change the state, call functions...
})
.catch((error) => {
console.log(error);
});
}, []);
return httpData;
};
export default useHttpReqHandler;
in your main file
import useHttpReqHandler from "...."
const MyFunc = () => {
const getData = useHttpReqHandler("URL");
return (
<div>
...
</div>
)
}
I hope it helps
the same thing will be with POSt, PUT, DELETE ... you will create functions for each method that will handle the Http req

Resources