React project- chatting app. Need advice on setting interval - reactjs

below is my main code for my project, which is a simple open chatting room.
This is a chatting client basically, which can only get chatting logs and post chats.
To log in, I request for an authorization key to the server and use that key to start chatting.
The thing that I want to do is to get the chatting logs from the server every 3 seconds.
So, after it retrieves chats every 3 seconds, the page should refresh with new chats.
However, this seems not to be working well for me.
If there is a good React pro who can solve this problem for me, please do.
import React from 'react';
import { withRouter } from 'react-router-dom';
import './Chat.css';
import InfoBar from '../InfoBar/InfoBar';
import Input from '../Input/Input';
import Messages from '../Messages/Messages';
const API_ENDPOINT = 'https://snu-web-random-chat.herokuapp.com';
let INTERVAL_ID;
const Chat = ({ token, setToken }) => {
const [ name, setName ] = React.useState('');
const [ message, setMessage ] = React.useState('');
const [ messages, setMessages ] = React.useState([]);
const [ lastEl, setLastEl ] = React.useState({});
React.useEffect(() => {
if (localStorage.getItem('username')) {
setName(localStorage.getItem('username'));
}
window.addEventListener('scroll', listenToScroll, true);
fetchData();
INTERVAL_ID = setInterval(() => {
fetchData();
}, 3000);
return () => {
window.removeEventListener('scroll', listenToScroll);
clearInterval(INTERVAL_ID);
};
}, []);
const fetchData = () => {
fetch(`${API_ENDPOINT}/chats?createdAtFrom=${lastEl.createdAt || ''}`)
.then((res) => res.json())
.then((msgs) => {
const updatedMsgs = messages.concat(msgs);
setLastEl(msgs[msgs.length - 1]);
setMessages(updatedMsgs);
});
};
const listenToScroll = (e) => {
const div = document.getElementById('messagesContainer');
// console.log(window.scrollY);
// const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
// const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
// const scrolled = winScroll / height;
};
const onLogin = (e) => {
e.preventDefault();
fetch(`${API_ENDPOINT}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `name=${name}`
})
.then((response) => response.json())
.then(({ key }) => {
if (key) {
setToken(true);
localStorage.setItem('__key', key);
localStorage.setItem('username', name);
}
})
.catch((err) => console.error(err));
};
const sendMessage = (e) => {
e.preventDefault();
if (message) {
fetch(`${API_ENDPOINT}/chats`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Key ${localStorage.getItem('__key')}`
},
body: `message=${message}`
})
.then((response) => response.json())
.then((res) => {
const obj = {
createdAt: res.createdAt,
message: res.message,
userName: res.user.name,
_id: res.user._id
};
setMessages([ ...messages, obj ]);
})
.catch((err) => console.error(err));
setMessage('');
}
};
const logout = () => {
localStorage.removeItem('__key');
localStorage.removeItem('username');
setToken(false);
};
const loadMessages = () => {
fetchData();
clearInterval(INTERVAL_ID);
};
return (
<div className="outerContainer">
<div className="innerContainer">
<InfoBar
name={name}
token={token}
handleInput={(e) => setName(e.target.value)}
handleLogin={onLogin}
handleLogout={logout}
/>
<Messages messages={messages} name={name} lastEl={lastEl} loadMore={loadMessages} />
{token && <Input message={message} setMessage={setMessage} sendMessage={sendMessage} />}
</div>
</div>
);
};
export default withRouter(Chat);

I can give u the advice to make a chat app with socket.io, not setInterval.
https://socket.io/get-started/chat

Related

React-paypal advanced integration errors

I have been trying to implement React-Paypal advanced integration for almost a week now but I keep getting an error. I did not use api from paypal sandbox, instead I'm calling our own api built with dotnet.
When I proceed with payment, order Id was created but the payment declined.
Working flow that I want to achieve is;
onClick Prepare for payment will generate all data that I need to process in the back end. Then, on render or onClick Pay, it will create an order including orderId and capture the payment.
Can anyone spot where I went wrong on my code below?
Error:
Checkout.jsx
import { useState } from "react"
import {
PayPalScriptProvider
} from "#paypal/react-paypal-js";
import CheckoutButton from "./CheckoutButton";
import "../styles/Checkout.css";
import NewCheckoutBtn from "./Checkout2";
const PrepareForPayment = () => {
const [clientId, setClientId] = useState(null)
const [clientToken, setClientToken] = useState(null)
const [merchantRef, setMerchantRef] = useState(null)
const [sessionHash, setSessionHash] = useState(null)
const [showData, setShowData] = useState(false);
const baseUrl = "http://local.payment.web"
const onClick = async () => {
console.log("onClick ran");
return await fetch(`${baseUrl}/api/Ppal/ReactApi/PrepareForPayment`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: JSON.stringify({
"curCode": "USD",
"orderAmount": 500
})
}).then(res => {
console.log("fetch Data : ", res);
return res.json()
}).then(data => {
console.log("fetch Data : ", data);
setShowData(true)
setClientId(data.ClientId)
setClientToken(data.ClientToken)
if (data.prepareForPayment) {
setMerchantRef(data.merchantRef)
setSessionHash(data.sessionHash)
}
}).catch(err => console.log(err))
}
return (
<>
<button onClick={onClick} disabled={showData ? true : false}>Prepare for payment</button>
{
clientToken && (
<PayPalScriptProvider
options={{
"client-id": clientId,
components: "buttons,hosted-fields",
"data-client-token": clientToken,
intent: "capture",
vault: false,
}}
>
<CheckoutButton merchantRef={merchantRef} sessionHash={sessionHash} />
</PayPalScriptProvider>
)
}
</>
)
}
export default PrepareForPayment
CheckoutButton.jsx
import { useState, useRef, useEffect } from "react";
import { usePayPalHostedFields, usePayPalScriptReducer } from "#paypal/react-paypal-js";
import "../styles/CheckoutBtn.css";
import { useCallback } from "react";
const CheckoutButton = ({ merchantRef, sessionHash }) => {
const [paid, hasPaid] = useState(false)
const [orderId, setOrderId] = useState(null)
const [supportsHostedFields, setSupportsHostedFields] = useState(null)
const [renderInstance, setRenderInstance] = useState()
const cardHolderName = useRef(null);
const hostedField = usePayPalHostedFields();
const [{ isResolved, options }] = usePayPalScriptReducer()
const paypal = window.paypal
const baseUrl = "http://local.payment.web"
const initPaypal = useCallback(async () => {
if (typeof supportsHostedFields === "boolean" && !!supportsHostedFields) {
const instance = await paypal.HostedFields.render({
createOrder: function() {
return fetch(`${baseUrl}/api/Ppal/ReactApi/CreateOrder2`, {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: merchantRef,
sessionHash: sessionHash,
orderId: orderId,
intent: "capture",
})
}).then(res => {
console.log("res from createOrder", res);
return res.json()
}).then(data => {
console.log("orderId from initialize : ", data?.orderId);
if (data?.createOrder) return setOrderId(data?.orderId)
}).catch(err => console.log(err))
},
styles: {
input: {
"font-size": "16pt",
color: "#3A3A3A"
},
".number": {
"font-family": "monospace"
},
".valid": {
color: "green"
}
},
fields: {
number: {
selector: "#card-number",
placeholder: "Credit Card Number"
},
cvv: {
selector: "#cvv",
placeholder: "CVV"
},
expirationDate: {
selector: "#expiration-date",
placeholder: "MM/YYYY"
}
}
})
setRenderInstance(instance)
}
}, [merchantRef, sessionHash, orderId, paypal, supportsHostedFields])
useEffect(() => {
if (isResolved) {
setSupportsHostedFields(paypal.HostedFields.isEligible());
}
}, [setSupportsHostedFields, options, isResolved, paypal]);
useEffect(() => {
initPaypal()
}, [initPaypal])
const handleClick = (e) => {
e.preventDefault()
console.log("Order id onclick : ", orderId);
renderInstance.submit().then((data) => {
console.log("Reach here?");
const captureOrder = async () => {
return await fetch(`${baseUrl}/api/Ppal/ReactApi/CaptureOrder`, {
mode: "cors",
method: "post",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
merchantRef: merchantRef,
sessionHash: sessionHash
})
}).then((res) => {
console.log("res from pay button : ", res);
return res.json()
}).then((data) => {
console.log("data from pay button : ", data);
if(data.isApproved) {
alert("Payment successful")
hasPaid(true)
}
if(!data.isApproved) alert("Payment declined")
if(data.isExpired) alert("Payment expired")
})
}
captureOrder().catch((err) => {
console.log(err)
})
return data
})
console.log("Card holder : ", cardHolderName.current.value);
console.log("merchant ref : ", merchantRef);
console.log("Order id onclick after : ", orderId);
};
return (
<form onSubmit={handleClick}>
<label htmlFor="card-number">Card Number</label>
<div id="card-number"></div>
<label htmlFor="expiration-date">Expiration Date</label>
<div id="expiration-date"></div>
<label htmlFor="cvv">CVV</label>
<div id="cvv"></div>
<button value="submit" id="submit" className="btn">
Pay with Card
</button>
</form>
)
};
export default CheckoutButton;
As others have pointed out, the error in your screenshot comes from this line inside of handleClick
console.log("Card holder : ", cardHolderName.current.value);
You've initialized cardHolderName with null.
const cardHolderName = useRef(null);
But then your code appears to do nothing with that ref. So that current value of the ref will always be null.
To fix the error, remove the reverence to cardHolderName.current.value, or set the value of the ref to an object with a value property.

Socket works the for a few seconds then fails

I've managed to establish a connection using socket. It works great for the first few seconds after that it runs super slow takes like almost 2-3 mins to complete a request. And then it produces this error continuously. The app doesn't crash it just runs slowly with the error displaying countless times.
Firefox can’t establish a connection to the server at ws://localhost:5000/socket.io/?EIO=4&transport=websocket&sid=9S6kqHJdHHXQgrobAAHp..
Error on console.
Main.js
function Home(props) {
const [Username , setUsername] = useState("")
const [SearchedData, setSearchedData] = useState()
const [Data, setData] = useState()
const socket = io('http://localhost:5000')
React.useEffect(() => {
// socket.current = io('http://localhost:5000')
socket.emit("content","yada")
socket.on("get-data", data => {
setData(data)
})
})
function NavBar(props){
const handleClick = (e) => {
const {id} = e.target
if(id === "Post-btn"){
if(Content.length > 0){
let data = {
Username: "yada", Content
}
props.socket.emit("store-data", data)
}
}
return(
Tags....
)}
function Content (props) {
const onLike = (e) => {
const { id } = e.target.dataset
const data = {
username: "yada",
id : id
}
// console.log(data)
props.socket.emit("like", data)
}
return(
Tags.....
)
}
server.js
mongoose.connect(process.env.MongoDB,
{ useNewUrlParser: true, useUnifiedTopology: true }).then(() => {
console.log("Database Connected")
}).catch(err => {
console.log(err)
});
const server = app.listen(process.env.Port, () => {
console.log("Connected on " + process.env.Port)
})
const io = socket(server, {
cors:{
origin: "http://localhost:3000",
credential: true,
}
})
let cuid;
io.on("connection", (socket) => {
socket.on("content", username => {
Comments.find({},(err, data) => {
if(!err)
socket.emit("get-data", data)
})
})
socket.on("store-data", data => {
const {Username, Content} = data
const newdata = new Comments({
userName: Username,
content: Content,
createdAt: new Date().toDateString(),
replies: []
})
newdata.save().then(data => {
for(const d in data)
if(d === "_id"){
Users.findOneAndUpdate({username: Username}, {$push: {UserContent: data[d]}}, {new: true}, (err, save) => {
if(err)
console.log(err)
else
console.log(save)
})
}
})
})
socket.on("like", data => {
const {username, id} = data
Users.findOne({username:username}, (err, data) => {
if(!err){
cuid = data['id']
console.log(cuid)
Comments.findByIdAndUpdate(id, {$set: {score: data['_id']}}, {upsert: true}, (err, d) => {
if(!err){
console.log(d)
}
})
}
})
})
})
Looking at the code provided, I noticed there is an useEffect without params. This may be causing a loop until the application crashes.
React.useEffect(() => {
// socket.current = io('http://localhost:5000')
socket.emit("content","yada")
socket.on("get-data", data => {
setData(data)
})
socket.on("Updated", data => {
setData(data)
})
}, []); <- this is missing
This empty array indicates that the content inside the useEffect will only run once.
More about this https://reactjs.org/docs/hooks-intro.html

React POST request, how to reconcile a timing error?

I have a react file tied to an express/node backend and SQL database. My backend is functioning correctly, all routes are verified with postman and the app has the ability to get, post, update, and delete. However, I am running into an issue with my front end now, specifically regarding my POST request.
Every time I make a post request the server/database are being updated correctly with the new applicant, which I can see populate the back end, but I am receiving the following error on the front end "Cannot read properties of undefined (reading 'store')" pertaining to my function labeled "TableList"
Somehow the TableList function which has the role of extrapolating only the unique stores that applicants are assigned too is picking up an "undefined" value for the new store assignment whenever a POST request is made. What is most confusing to me is that if I then reload the page manually the front end displays correctly. Is this a timing issue related to async?
Below is my main file where all state is held - relevant functions are TableList and those containing the markup New Vehicle Form
import { useState, useEffect, useImperativeHandle } from "react";
import useFetch from "../Components/Fetch/fetch";
import List from "../Components/Sections/list";
import Intro from "../Components/Sections/intro";
import SearchForm from "../Components/Forms/searchForm";
import AddForm from "../Components/Forms/addForm";
import UpdateForm from "../Components/Forms/updateForm";
import { parseDate } from "../Components/Utils/index";
const Home = () => {
/* DATE & TIME FORMAT */
var today = new Date();
const displaytime = parseDate(today);
/*INITIAL STATE*/
const { data, setData, isPending } = useFetch(
`http://localhost:5000/api/applicants`
);
/*NEW VEHICLE FORM: TOGGLE FORM DISPLAY*/
const [showAddForm, setShowAddForm] = useState(false);
const handleAddForm = () => {
setShowAddForm(!showAddForm);
};
/*NEW VEHICLE FORM: POST REQUEST, DECLARING STATE*/
const initialFormState = {
store: "",
first_name: "",
last_name: "",
position: "",
recruiterscreen_status:"",
testing_status:"",
interview_status:"",
backgroundcheck_status:"",
drugscreen_status:"",
paperwork_status:"",
date_in: "",
currentdate: displaytime,
notes:"",
};
const [formData, setFormData] = useState({ ...initialFormState });
/*NEW VEHICLE FORM: POST REQUEST, UPDATING STATE*/
const handleFormChange = (event) => {
const { name, value } = event.target;
setFormData({
...formData,
[name]: value,
});
};
/*NEW VEHICLE FORM: POST REQUEST, TRIGGER RERENDER*/
const confirmpost = (applicant) => {
setData([...data, applicant])
console.log(data)
};
/*NEW VEHICLE FORM: POST REQUEST, SUBMIT TO SERVER*/
const handleFormSubmit = (event) => {
event.preventDefault();
const applicant = formData;
console.log(applicant);
fetch(`http://localhost:5000/api/applicants/`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(applicant),
})
.then((response) => response.json())
.then((response) => console.log("Added Successfully"))
.then((applicant) => confirmpost(applicant))
.then(()=>handleAddForm())
.catch((error) => console.log("Form submit error", error));
setFormData({ ...initialFormState });
};
/*DELETE APPLICANT: FRONT END RERENDER*/
const deleteApplicant = (id) => {
const updatedTable = data.filter((item) => item.applicant_id != id);
setData(updatedTable);
};
/*DELETE APPLICANT: SERVER REQUEST*/
const handleDelete = (id, stock) => {
fetch(`http://localhost:5000/api/applicants/${id}`, {
method: "DELETE",
})
.then((response) => console.log("Deleted Applicant"))
.then(() => deleteApplicant(id));
};
/*UPDATE FORM: TOGGLE FORM DISPLAY, ALSO GRAB USER ID*/
const [showUpdateForm, setShowUpdateForm] = useState(false);
const [selectedApplicant, setSelectedApplicant] = useState(null)
const [selectedApplicantName, setSelectedApplicantName] = useState(null)
const handleUpdateForm = (applicant_id, first_name,last_name) => {
setSelectedApplicant(applicant_id)
setSelectedApplicantName(first_name + " "+ last_name)
setShowUpdateForm(!showUpdateForm);
console.log(`Show Form: ${showUpdateForm}`)
};
/*UPDATE FORM: DECLARE INITIAL STATE*/
const initialStatusState = {
recruiterscreen_status:null,
testing_status: null,
interview_status:null,
backgroundcheck_status: null,
drugscreen_status: null,
paperwork_status:null,
notes:null,
};
/*UPDATE FROM: CHANGE APPLICANT STATE*/
const [statusData, setStatusData] = useState({ ...initialStatusState });
const handleStatusChange = (event) => {
const { name, value } = event.target;
setStatusData({
...statusData,
[name]: value,
});
};
/*UPDATE FORM: SUMBIT TO SERVER*/
const handleUpdate = (id) => {
fetch(`http://localhost:5000/api/applicants/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(statusData),
})
.then((response) => response.json())
.then(() => confirmUpdate(id))
.then((response) => console.log(`Updated Successfully to
recruiterscreen_status: ${statusData.recruiterscreen_status},
testing_status: ${statusData.testing_status},
interview_status: ${statusData.interview_status},
backgroundcheck_status: ${statusData.backgroundcheck_status},
drugscreen_status: ${statusData.drugscreen_status},
paperwork_status: ${statusData.paperwork_status},
notes:${statusData.notes},`));
setStatusData({ ...initialStatusState });
};
/*UPDATE FORM: FRONT END RERENDER*/
const confirmUpdate = (id) => {
const updatedTable = data.map((item) =>
item.applicant_id != id
? item
: {
...item,
recruiterscreen_status: statusData.recruiterscreen_status,
testing_status: statusData.testing_status,
interview_status: statusData.interview_status,
backgroundcheck_status: statusData.backgroundcheck_status,
drugscreen_status: statusData.drugscreen_status,
paperwork_status: statusData.paperwork_status,
notes:statusData.notes,
}
);
setData(updatedTable);
handleUpdateForm(id)
};
/* NOTES POP UP */
const [notesIsOpen, setNotesIsOpen] = useState(false)
const togglePopup = () => {
setNotesIsOpen(!notesIsOpen)
}
/*LIST OF ACTIVE STORES*/
const unique = (value, index, self) => {
return self.indexOf(value) === index;
};
const TableList = (data) => {
const list = data.map((element) => element.store);
const uniquelist = list.filter(unique).sort();
console.log(uniquelist)
return uniquelist;
};
const stores = TableList(data)
/*RUN*/
return (
<div>
<Intro displaytime={displaytime} />
<div className="add-applicant">
<button className="add-applicant-btn" onClick={handleAddForm}>
Add Applicant
</button>
</div>
<SearchForm data={data} setData={setData} />
{showAddForm ? (
<AddForm
formData={formData}
setFormData={setFormData}
handleFormChange={handleFormChange}
handleFormSubmit={handleFormSubmit}
/>
) : null}
{showUpdateForm ? (
<UpdateForm data={data} selectedApplicant={selectedApplicant} selectedApplicantName={selectedApplicantName} handleUpdateForm={handleUpdateForm} statusData={statusData} handleStatusChange={handleStatusChange} handleUpdate={handleUpdate} />
) : null}
<hr></hr>
{!isPending ? (
stores.map((element) => (
<div>
{" "}
<List
cut={element}
data={data}
isPending={isPending}
handleDelete={handleDelete}
handleUpdate={handleUpdate}
handleStatusChange={handleStatusChange}
showUpdateForm={showUpdateForm}
handleUpdateForm={handleUpdateForm}
togglePopup={togglePopup}
notesIsOpen={notesIsOpen}
TableList={TableList}
/>
</div>
))
) : (
<div>Loading</div>
)}
</div>
);
};
export default Home;
In the fetch chain the logging step which injects an undefined into the chain.
The logging step needs to pass on its input data:
fetch(`http://localhost:5000/api/applicants/`, { }) // Elided
.then((response) => response.json())
.then((response) => {
console.log("Added Successfully")
return response
)
.then((applicant) => confirmpost(applicant))

How to fetch api via looped callbacks with React functional components

So I have a 40+ loop that's calling another component to display images. Each image has an ID and with that ID I can get more information about the image like Name and description via another API call.
When DisplayImage gets called I want it to call another callback function that will send out API calls for that image's metadata, store it in a variable and display it as an H1 tag.
return (
<div>
{array.map(index) => {
// Some Other Code That return a TokenID //
<>
{displayImage(tokenId)}
</>
</div>
})
const displayImage = (tokenId) => {
const imageName = GetURI(tokenId)
return (
<div className="token-container">
<h1>{imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}
const GetURI = async (tokenId) => {
const res = await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
}
The data is being displayed on the console but now I'm running into an infinite loop issue that I know UseEffect can solve but I can't quite figure it out. I managed to display the data on the console with UseEffect using the [] attribute but don't know how to display the data. Any help would be amazing. Thank you!
Two things useful to your situation
functions declared outside the component aren't recreated each render
useState and useEffect pairing limits calls to API to only when tokenId changes
// Put this function outside the component
// so it does not need a useCallback
// i.e not reconstructed each render of DisplayImage
const GetURI = async (tokenId) => {
...
});
const DisplayImage = (tokenId) => {
const [imageName, setImageName] = useState()
// limit calls to API to when tokenId changes
// and if eslint complains add GetURI to dependency list
// - but GetURI never changes, so no un-needed calls from it
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};
You can also abstract to custom hook useImageName()
const GetURI = async (tokenId) => {
...
});
const useImageName = (tokenId) => {
const [imageName, setImageName] = useState()
useEffect(() => {
setImageName(GetURI(tokenId))
}, [tokenId, GetURI])
return imageName
})
const DisplayImage = (tokenId) => {
const imageName = useImageName(tokenId)
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
};
BTW in GetURI this
return (data.name || [])
looks like should be
return data.name || ''
Is a different approach ok? I'd put display image into its own component.
const DisplayImage = ({tokenId: {_tokenId}}) => {
const imageName = GetURI(_tokenId)
const GetURI = useCallback(async () => {
await fetch("https://api"+tokenId , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}).then(data => {
console.log(data)
return data.json();
})
.then(data => {
return (data.name || [])
})
.catch(err => {
console.log(err);
});
})
});
useEffect(() => {
if (_tokenId) GetURI();
}, [GetURI]);
return (
<div className="token-container">
<h2>{imageName}</h2>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${_tokenId}`} />
</div>
)
};
and then
return (
<div>
{array.map(index) => {
//Some Other Code//
<DisplayImage tokenId={tokenId} />
</div>
})
You should probably cache the response from GetURI(tokenId). No need to ask twice for the same URI when using the same tokenId.
An easy way is using react-query:
Setup in App.js:
// App.js
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
Then use in a DisplayImage component (instead of inline function):
// DisplayImage.js
import { useQuery } from 'react-query'
export function DisplayImage(tokenId) {
const { isLoading, error, data: imageName } = useQuery(['images', tokenId], GetURI(tokenId))
return (
<div className="token-container">
<h1>{isLoading ? 'loading...' : imageName}</h1>
<img className="artwork" width="250px" src={`https://ipfs-asdf/${tokenId}`} />
</div>
)
}
I found the best way to go about it with everyones help on here so thanks!
I put the GetURI function inside the show image component, and had a useEffect method call GetURI every time there was a new token ID, then I set a state variable to whatever was returned.
No loops, no errors 👌
const DisplayImage = (data) => {
const [nftMetadata, setNftMetadata] = useState();
const GetURI = async (data) => {
const nftURI = await data.drizzle.contracts.Contract.methods.tokenURI(data.tokenId).call()
await fetch(nftURI , {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"Access-Control-Allow-Origin": "*"
},
})
.then(data => {
return data.json();
})
.then(data => {
return setNftMetadata(data || []);
})
.catch(err => {
return console.log(err);
});
});
useEffect(() => {
GetURI(data);
}, [data.tokenId])
return (
<div className="token-container">
<h2>{nftMetadata.name}</h2>
<img className="artwork" width="450px" src={`https://ipfs:/whatever/${nftMetadata.image}`} />
</div>
);
};
return (
<div>
{array.map(index) => {
// Some Other Code That returns a TokenID //
<>
<DisplayImage address={drizzle.contractList[0].address} tokenId={tokenId} drizzle={drizzle} drizzleState={drizzleState}/>
</>
</div>
})

Wait for get request response before continuing with a post request in axios

I have tried to use async/await in the createSwap function but it did not work for me. Before creating a request, I want to run the getSlotDetails function to set the slotDets so that it can be used in the post request below. However, the createSwap function does not wait for the getSlotDetails function to complete before sending the post request. How do I fix this?
const [slotDets, setSlotDets] = useState([]);
const getSlotDetails = (moduleCode, slotId, slotType) => {
axios
.get(`https://api.nusmods.com/v2/2020-2021/modules/${moduleCode}.json`)
.then((response) => response.data)
.then((data) => data.semesterData[0])
.then((semesterData) => semesterData.timetable)
.then((timetable) =>
timetable.filter(
(slot) => slot.classNo === slotId && slot.lessonType == slotType
)
)
.then((result) => {
setSlotDets(result);
});
};
const createSwap = (
moduleCode,
slotType,
currentSlot,
desiredSlots,
completed,
reserved
) => {
dispatch(createRequest());
getSlotDetails(moduleCode, currentSlot, slotType);
axios
.post(
"http://localhost:3001/api/v1/swaps",
{
module_code: moduleCode,
slot_type: slotType,
current_slot: currentSlot,
desired_slots: desiredSlots,
completed: completed,
reserved: reserved,
venue: slotDets.venue,
startTime: slotDets.startTime,
endTime: slotDets.endTime,
day: slotDets.day,
},
{
headers,
}
)
.then((response) => {
console.log(response.data);
dispatch(createSuccess());
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
})
.catch((error) => {
console.log(error.response.data);
dispatch(createFail(error.response.data));
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
});
};
const makeTwoRequests = async () => {
try{
const firstResponse = await axios.get(FIRST_URL);
if(firstResponse.status === 200){
const firstResponseData = firstResponse.data;
const secondResponse = await axios.get(SECOND_URL);
if(secondResponse.status === 200){
const secondResponseData = secondResponse.data;
}
}
}
catch(error){
console.log(error)
}
}
maketwoRequests()
firstResponseData and secondResponseData can be state variables instead of const for better access throughout the Component

Resources