I am creating a chat application in React. I am using the useEffect-hook to update the messages (all it really does is fetch them from the JSON-server). I want them to be updated every time someone in the room sends a new message.
This is one alternative I have:
useEffect(() => {
fetch('http://localhost:8000/messages/')
.then(res => {
return res.json();
})
.then(data => {
data = data.filter((msg) => msg.room === room);
setData(data);
})
.catch(err => {
console.error(`Error: ${err}`);
})
divRef.current.scrollIntoView({ behavior: 'smooth' });
}, []);
"data" is a list of messages. This shows all the messages when you enter the room, but does not load when you pass a new message. Assumingly because of the empty list at the end. Therefore I tried this:
In another component, I have a variable "sent", which is set to true every time you send a message, like this:
const onSubmit = (e) => {
e.preventDefault();
const data = {author: user, body: msg, room }
setSent(true);
fetch(`http://localhost:8000/messages/`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
})
.then(response => {
response.json();
setSent(false);
})
.catch(err => console.error(`Error: ${err}`));
setMsg('');
}
So every time you send a message, it is set to 'true', and as soon as it has been successfully sent, it is set back to 'false'. I then passed it as a prop to the component I use useEffect:
<div className='chat-main'>
<Messages user={user} room={room} sent={sent} />
</div>
Then I put the "sent"-variable in the list at the bottom of the useEffect-hook. This updates the messages for the user who sends a message, but not for the others (because, of course, "sent" only changes if you send a message)
What can I do here? Is there a way?
Related
I have this code that runs for each user
exports.placeStake = async(req, res) =>{
const { amount, playTime, gameStaked, stake, Id} = req.body
await Stake.create({
amount:amount,
playTime: playTime,
stake:stake,
Id:Id,
ref:crypto.randomBytes(10).toString("hex"),
status:'pending',
userId:req.user.id,
}).then(()=>{
res.status(200).send('stake placed');
}).then(()=>{
setTimeout(() => {
axios
.get(`https://v3.football.api-sports.io/fixtures?id=${Id}`, {
headers: {
'x-rapidapi-host': 'v3.football.api-sports.io',
'x-rapidapi-key': '58xxxxxxxxxxxxxxxxx'
},
})
.then((response) => {
// update the user database with response
}).catch((error) => {
console.log(error)
});
},*2 hours*);
}).catch(function (error) {
console.log(error);
if (error) {
res.status(400).send(error);
}
});
}
After 2 hours from when the game is staked I want to make an Api call in the settimeout to check the game and update the user's account
What I am confused about is if the settimeout is evaluated for each user, if not how to make is so?
First of all you assume there won't be any process interruptions for 2 hours. Like restart, crash, whatever. Extremely fragile setup.
Second if you want to run anything for each, you need a loop. I don't see any loops here.
I have an app that allows a logged in user to upgrade their account by subscribing to a 'basic' or 'premium' subscription. Once they subscribe they can then click on a "Manage Billing" button and it will take them to a Billing Portal where they can cancel, or upgrade their subscription.
The issue that I am running into is that I am trying to make the customer be dynamic. So where it says customer: 'cus_IZvOkC9VtDRXUi', I can instead have something like customer: customer, where customer is a dynamic variable.
router.post('/customer-portal', async (req, res) => {
// const id = req.body.id
// console.log(req.body, 'ID HERE')
// User.findBy({ id })
// .then(found => {
// console.log(found, 'I FOUND YOU')
// })
// .catch(error => {
// console.log(error, 'error here on portal')
// })
// whatever customer is logged in, this needs to be the CUSTOMER line 45 - DYNAMIC
const session = await stripe.billingPortal.sessions.create({
customer: 'cus_IZvOkC9VtDRXUi',
return_url: 'http://localhost:3000/my-profile',
})
res.redirect(session.url)
const sessionURL = session.url
console.log(sessionURL,'this is session')
// console.log(session, 'this is the session')
// console.log(req,'this is req')
// res.status(302).redirect(sessionURL)
// next()
})
The problem is that when I try and send headers (so I can send the ID of the currently logged in user ID from the frontend), the req.body is an empty object and I can't see the ID. See frontend code here:
const state = useSelector(state => state)
const id = state.auth.user.id
const handlePortal = (e) => {
e.preventDefault()
console.log(id, 'JSJDHDHDHDHDHDHDH')
return fetch('http://localhost:5000/api/stripe/customer-portal', {
// mode: 'no-cors',
method: 'post',
// headers: {
// 'Content-Type': 'application/json',
// },
body: JSON.stringify({
id: id
})
})
.then((response) => {
console.log(response, 'this is the response')
const url = response.url
console.log(url, 'URURUIRIRLL')
// express cant force the front-end to redirect.
window.location = url
// return response.json()
})
.catch((error) => {
console.log(error.message, 'There was a dumb error')
})
}
The headers are commented out right now, but as soon as I add them in, I get this error:
CORS ERROR
What is super weird is this exact setup works when I create a Stripe Customer. I send the ID from the frontend at id: currentUserId. See code below:
const state = useSelector(state => state)
const currentUserId = state.auth.user.id
const handleSubmit = e => {
e.preventDefault()
return fetch(`http://localhost:5000/api/stripe/create-customer/`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email,
id: currentUserId
})
})
.then((response) => {
console.log(response, 'this is response handlesubmit')
return response.json()
})
.then((result) => {
setCustomer(result.customer)
console.log(result, 'THIS IS RESULT on register CUSTOMER')
})
}
Then on the backend I have my /create-customer endpoint and pull the id by req.body.id, then find the currently logged in user, then add the customer id given by stripe to the user table. This works fine without any CORS issues. See backend endpoint here:
router.post('/create-customer', async (req, res) => {
const id = req.body.id
const customer = await stripe.customers.create({
email: req.body.email,
})
res.send({ customer })
User.findBy({ id })
.then(found => {
User.updateStripeID(id, changes)
.then(changedUser => {
console.log(changedUser, 'changed!', id, changes)
})
.catch(error => {
console.log(error, 'this is stupid')
})
})
.catch(error => {
console.log(error, 'there was an error on catch', error.message)
})
})
So my question is, how do I get this working? Or how do I get my currently logged in user to the backend another way?
Couple things to note:
I do have a CORS extension that I am using in Chrome. The reason is that the my frontend will not even redirect to the Billing Portal and will throw an 'access-control-allow-origin' error. I have tried every solution on every stack overflow page about this. Literally. Spent days trying almost every solution about CORS issues. They do not work and I hope that when the app deploys live it won't have that redirect issue.
If you could not already tell my frontend is React, backend is NodeJS, and I am using Knex/SQLite3 for database tables/migrations/seeds etc.
Any help would be appreciated!
i am getting the data from my rails API backend and what i want to do is reload that get request every 15s , so if something changes on a backend ( for example i make a post request to my backend in another route) it reloads and gets the current data .
My created :
created() {
if (!localStorage.signedIn) {
this.$router.replace("/");
} else {
this.$http.secured
.get("/api/v1/records")
.then(response => {
console.log(response.data);
this.records.splice(0, this.records.length - 1, ...response.data);
})
.catch(error => this.setError(error, "Something went wrong"));
this.$http.secured
.get("/api/v1/templates")
.then(response => {
this.templates = response.data;
})
.catch(error => this.setError(error, "Something went wrong"));
this.$http.secured
.get("/api/v1/data")
.then(response => {
this.datas = response.data;
})
.catch(error => this.setError(error, "Something went wrong"));
}
},
Could you help me with implementing a setInterval to my get requests?
thanks
Try to use the setInterval, like:
mounted() {
this.intervalData = setInterval(this.getdata, 15000)
},
destroyed() {
clearInterval(this.intervalData)
},
methods: {
getData() {}
},
More smart solution could be: use POST request in nuxt proxy server or in your backend, like axios.post('/data', payload) and connect the websockets, you can use pusher for that. The final logic is: user add some data => post to server => server emits the websockets event => vuex listen to the event and the data will be reactive in all tabs.
When i'm going to localhost:3000/api/categories i'm getting an empty array, but when i log my products there is alot of data inside the object. Anyone knows what i'm doing wrong? Thanks!
let products = getData()
function getData() {
return fetch('some url',
{
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}
).then(res => res.json())
};
app.get(('/api/categories'), (req, res) => {
products.then(console.log);
res.send(products);
products.then(console.log);
});
products is a promise. You can't send it to the client via res.send.
Instead, do what you're doing when you log it: use then:
app.get(('/api/categories'), (req, res) => {
products
.then(data => res.send(data))
.catch(error => {
// Send an error
});
});
Note that your code gets the products once, at startup, and then responds to the request with that static set of products.
If you want to get the products in response to the request from the client, remove the
let products = getData();
and put it in the get handler:
app.get(('/api/categories'), (req, res) => {
this.getData()
.then(data => res.send(data))
.catch(error => {
// Send an error
});
});
That repeats the request each time the client calls your server.
Of course, you might consider a middle ground, keeping and reusing the data for X seconds...
This is a very very annoying thing, i'm trying to solve it for hours right now. Here's the code:
//ExpressJS code
app.post('/newname', (req, res) => {
const {name, type, id} = req.body;
console.log(name, type, id)
knex('fl').insert({
name, type, id,
...type === 'category'? {timeValue: req.body.timeValue, timeType: req.body.timeType} : {}
})
.then(() => {
console.log("bar");
return knex('fl').select('*').where('status', 'available')})
.then(data => res.json(data))
.catch(err => console.log(err))
})
//React code
possibleName = (event) => {
this.setState({
possibleName: event.target.value
})
console.log(this.state.possibleName)
}
complete = () => {
if(Boolean(this.state.possibleName)){
console.log(this.state.possibleName)
fetch('http://localhost:3001/newname', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
name: this.state.possibleName,
type: this.state.type,
id: this.props.id,
...this.state.type === 'category'? {timeValue: this.props.timeValue, timeType: this.props.timeType}:{}
})
})
.then(res => res.json())
.then(data => {
console.log("foo");
this.props.dispatch(getAction(data));
this.setState({
create: 'none',
zindex: 0,
possibleName: ''
})
})
.catch(err => console.log(err))
}
}
//...
//...
<input type='text' value={this.state.possibleName} onChange={this.possibleName}/>
<div onClick={this.complete}></div>
So... The first time the div is clicked, everything works fine. All the logs are in the console. The second time, the complete()'s first log happens, but it seems like the fetch isn't happening. What's the reason? Something blocks the second fetch? If i try it with Postman, with the same format of req.body, everything works fine every time i try it. So i don't know what will be the problem.
Another thing that might the source of the problem i think, is that there's a dispatch. It's possible that redux don't let the fetch to finish? I mean the first fetch begins, but not completes, so if i fetch second time, it get into query, and starts when the fetch before finishes?