Why fetch isn't working second time? - javascript

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?

Related

How to globally activate useEffect in React?

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?

Is there a way to allow headers when doing a fetch request to the Stripe Billing Portal?

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!

Getting empty array from get

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...

Saving data from JSON end point

I am trying to map over the returned json and save the id into profile/profiles. However it does not seem to be mapping over the the data correctly, id: ${ profile.id } this bit needs to be changed? Any help is much appreciated.
Is their a online tool that can help with me this?
API request:
// Grabs company data from the json url
private getProfiles() {
let config = {
headers: {'Authorization':'Bearer AQVVEqNXTWVYPpPYivKNWVO8jsTx2eveV3kBg'}
}
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response =>
response.data.map(profile => ({
id: `${ profile.id }`
}))
)
.then(profiles => {
this.setState({
profiles
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
}
Json data returned:
{
"localizedLastName": "King",
"id": "fm0B3D6y3I",
"localizedFirstName": "Benn"
}
When I console log the response.data
If the only data returned from your endpoint is the JSON you posted, then you don't have an array to map over.
You have a single object.
I've never used the axios library before, but looking at the source code response.data should be the JSON-parsed responseText from the XHR request:
https://github.com/axios/axios/blob/4f189ec80ce01a0275d87d24463ef12b16715d9b/lib/adapters/xhr.js#L51-L53
https://github.com/axios/axios/blob/4f189ec80ce01a0275d87d24463ef12b16715d9b/lib/defaults.js#L61
And now I see that you have posted response.data and it matches what I'd expect.
With that in mind I'd suggest handling it like this:
// Grabs company data from the json url
private getProfiles() {
let config = {
headers: {'Authorization':'Bearer AQVVEqNXTWVYPpPYivKNWVO8jsTx2eveV3kBg'}
}
axios
.get("https://cors-anywhere.herokuapp.com/" + "https://api.linkedin.com/v2/me", config)
.then(response => ({
id: profile.id
}))
.then(profiles => {
this.setState({
profiles
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
}
What you're getting back is a single profile though. If you need profiles to be an array you'll need to put the response in an array.
I don't get it, what you are trying to do. In the map you have a callback function, but as I see you wrote there an object. If you are wanting to rewrite the current profile's id then write this:
response.data.map(profile => ({
profile.id = `${ profile.id }`;
}))
But if you want it to make a variable then this:
response.data.map(profile => ({
let id = `${ profile.id }`;
}))

update dom to render results after api request

SOLVED: by adding this.tasks = resp.data in the functions so that it updates to the new state...
i'm currently working on a simple todo-list app in vuejs and i'm looking for a way to update the dom in a smooth way after doing the api request. The only way i've been able to display the changes directly after they've been made is by putting location.reload() in the response. I've been looking over some examples and guides and people seem to be able to do this with .bind(), but it's not working for me and i'm not content with the page flashing on every change you make.
//deletePost works for displaying changes but i don't want the page to flash on every update
deletePost(id) {
axios.delete(`http://localhost:3000/tasks/${id}`)
.then((resp) => {
console.log(resp.data)
location.reload();
})
.catch((err) => {
console.log(err)
})
},
//this is how i've seen people doing it, but it's not working for me.
updatePost(selected, id) {
axios.put(`http://localhost:3000/tasks/${id}`,{ status: selected } )
.then(function(response){
console.log('saved successfully')
}.bind(this));
}
},
Any ideas?
You shold have an array of tasks in your Vue component. Sending an http request deletes the resource from the server, but not locally. To delete the resource inside your component you'll need to do it in the .then() part for example like this:
data() return {
tasks: []
},
deletePost(id) {
axios.delete(`http://localhost:3000/tasks/${id}`)
.then((resp) => {
console.log(resp.data)
// Here we delete the task from the component locally
// Note that we only want to delete it if the request is successful
let index= this.tasks.find(task => task.id === id)
this.tasks.splice(index,1);
})
.catch((err) => {
console.log(err)
})
},
//this is how i've seen people doing it, but it's not working for me.
updatePost(selected, id) {
axios.put(`http://localhost:3000/tasks/${id}`,{ status: selected } )
.then(function(response){
console.log('saved successfully')
}.bind(this));
}
},
Thanks for replying to my first post here so quickly, of course i should've provided the whole script and not just the api request...
data () {
return {
tasks: [],
formValue: '',
selected: ''
}
},
created () {
this.fetchData()
},
watch: {
'$route': 'fetchData',
},
methods: {
fetchData () {
axios.get('http://localhost:3000/tasks')
.then((resp) => {
this.tasks = resp.data
console.log(resp.data)
})
.catch((err) => {
console.log(err)
})
},
deletePost(id) {
axios.delete(`http://localhost:3000/tasks/${id}`)
.then((resp) => {
console.log(resp.data)
// Here we delete the task from the component locally
// Note that we only want to delete it if the request is successful
let index= this.tasks.find(task => task.id === id)
this.tasks.splice(index,1);
})
.catch((err) => {
console.log(err)
})
},
//updates post status
updatePost(selected, id) {
axios.put(`http://localhost:3000/tasks/${id}`,{ status: selected } )
.then(function(response){
console.log('saved successfully')
}.bind(this));
}
},
}

Categories

Resources