State is being changed, but display not updating - reactjs

I've seen quite a few posts about this, but none of the solutions seem to work for me.
I have a render method that is being mapped to list the different sections stored in a state(this part works as expected):
render() {
return (
<ThemeProvider theme={theme}>
<Div>
<hr />
<div>
{this.state.sections.map(section => (
<div
className="mb-3"
key={section.section_title}
>
<h3>{section.section_title}</h3>
</div>
))}
</div>
)
}
However, I have a modal that allows you to create a new section by giving it a name and clicking submit. That does create it and add it to my database table as expected. But, then when I run the method to pull that data down, and change the state to include the new section, it works, and does indeed change the state to include the new section. But it does not update the display unless I reload the page. Can anyone see why?
getProjectSections(projId) {
fetch(API_URL + `/billingcalculator/sections/distinct/${projId}`)
.then((res) => {
if (!res.ok) {
throw new Error()
}
return res.json()
})
.then((result) => {
let listedSections = [...result];
this.setState({ sections: listedSections });
})
.catch((error) => {
console.log(error);
})
}
the getProjectSections() runs when you click the submit button a creating a new section which runs this:
handleSectionCreateSave() {
fetch(API_URL + `/billingcalculator/section/create`, {
method: "PUT",
body: JSON.stringify({
projectId: this.props.billProjId,
sectionTitle: this.state.newSectionTitle
}),
headers: { "Content-Type": "application/json" },
})
.then((res) => {
if (!res.ok) {
throw new Error();
}
return res.json();
})
.then((data) => console.log(data))
.catch((err) => console.log(err))
.then(this.getProjectSections(this.props.billProjId))
.then(this.setState({ showSectionModal: false }))
.catch((err) => console.log(err));
}

You are calling state updates before request happens:
handleSectionCreateSave() {
fetch(API_URL + `/billingcalculator/section/create`, {
method: "PUT",
body: JSON.stringify({
projectId: this.props.billProjId,
sectionTitle: this.state.newSectionTitle
}),
headers: { "Content-Type": "application/json" },
})
.then((res) => {
if (!res.ok) {
throw new Error();
}
return res.json();
})
.then((data) => console.log(data))
.catch((err) => console.log(err))
// you called these function now, instead after fetch
// use () =>
.then(() => this.getProjectSections(this.props.billProjId))
.then(() => this.setState({ showSectionModal: false }))
.catch((err) => console.log(err));
}

Related

request failed with status code 422 is returned by axios delete in react.js

I list some room_name from the backend with React.js
What I want to implement is that user can delete room_name when user clicks the trash can icon.
Issue/error message
Request failed with status code 422
It's strange
As shown in the picture, I can see "the body sent to server section" on the console.
I can confirm that the room_name has been sent properly.
I believe the data you are sending is correct.
Even if I try with Postman with the same URL and data, I can delete it successfully.
const SettingGetRoomName = () => {
const [room_name, setRoomName] = useState([]);
const DeleteRoom = async(data) => {
console.log("Body sent to server", {
home_rooms: [data.item],
})
await axios.delete("xxx.com",
{
home_rooms: [data.item],
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${cookies.get('accesstoken')}`
},
})
.then(result => {
alert('Succeded delete room!');
console.log('Succeded delete room!');
})
.catch(err => {
alert('Missed delete room!');
console.log(err);
console.log('Missed delete room!');
});
}
const getRoomName = async(data) => {
await axios.get("xxx.com",
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${cookies.get('accesstoken')}`
},
})
.then(result => {
console.log(result.data)
setRoomName(result.data.home_rooms);
})
.catch(err => {
console.log(err);
});
}
useEffect(() => {
getRoomName();
},[]);
return (
<>
{room_name.map((item,i) =>
<div key={i} className="flex_setting_get_room_box">
<div className="my_hubs">
<p className="">{item}</p>
<img src={ic_delete} onClick={(e)=>DeleteRoom({item})}/>
</div>
</div>
)}
</>
);
}
export default SettingGetRoomName;
Check this link and the axios docs. The second parameter of axios.delete() is not the request body, but rather the request options. Simply add the body on the data key of the request options:
await axios.delete("xxx.com", {
data: {
home_rooms: [data.item]
},
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${cookies.get('accesstoken')}`
},
})
.then(result => {
alert('Succeded delete room!');
console.log('Succeded delete room!');
})
.catch(err => {
alert('Missed delete room!');
console.log(err);
console.log('Missed delete room!');
});

React upload and display image

I don’t understand how to upload a photo correctly and then upload it to the page.
I'm a beginner, can you please tell me what I did wrong?
const [photo, setPhoto] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
const users = {name, email, phone, position, photo}
setIsPending(true);
fetch("http://localhost:8000/users", {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify(users)
}).then(() => {
console.log('well');
setIsPending(false);
})
}
<form className="form" onSubmit={handleSubmit}>
<UploadFile
name="file"
onChange={(e) => setPhoto(e.target.files[0])}
value= {photo}
/>
<Button type="submit"/>
</form>
First of all you have to find a service that allows you to upload a file.
for example: https://api.imgur.com/endpoints/image/
there instructions inside.
However if you want to use fetch method I will give you an example how it should look like.
const handleSubmission = () => {
const formData = new FormData();
formData.append('File', selectedFile);
fetch(
'https://freeimage.host/api/1/upload?key=<YOUR_API_KEY>',
{
method: 'POST',
body: formData,
}
)
.then((response) => response.json())
.then((result) => {
console.log('Success:', result);
})
.catch((error) => {
console.error('Error:', error);
});
};
};
After recieving response from api service which is this part
.then((response) => response.json())
.then((result) => {
console.log('Success:', result);
})
.catch((error) => {
console.error('Error:', error);
});
You can set your state with the response url like this.
.then((response) => response.json())
.then((result) => {
console.log('Success:', result);
setPhoto(result.data.imageurl)
})
.catch((error) => {
console.error('Error:', error);
});
In the end you can use that image anywhere you want.
<img src={photo} />

Unhandled Rejection (TypeError): Cannot read property 'error' of undefined

I'm fairly new to React and I've been trying to create a SignUp page, however, I'm stuck in this error. Can someone give me any indication on what I should do in order to solve this error?
Signup Method:
// = Action =
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
}
Rewrite Signup method (ps: I only changed the .catch handler)
`
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err =>
console.log(err));
return err;
}
`
You need to wrap up your fetch logic inside a Promise to return a value to the caller.
export const signup = user => {
return new Promise((resolve, reject) => {
fetch(`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => response.json())
.then(jsonData => resolve(jsonData))
.catch(err => resolve({error: `something went wrong err : ${err}`}));
})
}
signup(user).then(data => {
if (data.error) {
// handle error case
} else {
// handle success case
}
})
Now your signup method will return a value. Your data variable won't be undefined anymore.
I hope it helps, feel free to add comments or ask me more details

i'm Trying to make react paypal button that change the billing amount on props change

i'm Trying to make react paypal button that changes the billing amount on props change.
I call the following component with props price and everytime the price change i would like to rerender the button to update the actual price.
const PaypalForm = props => {
let paypalRef = useRef();
useEffect(() => {
window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: "test",
amount: {
currency_code: "USD",
value: props.price
}
}
]
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
console.log(order);
},
onError: err => {
setError(err);
console.error(err);
}
})
.render(paypalRef.current);
}, [props.price]);
return (
<Row className="justify-content-center">
{error && <div>Uh oh, an error occurred! {error.message}</div>}
<div ref={paypalRef} />
</Row>
);
};
Everything is working except that a new button is created and added in the bottom of old one at each props change. I would like my new button to replace the old one.
You can pass the amount to the forceRerender property of the button and the button will rerender each whenever the amount is updated.
You should really just use react-paypal-button-v2
It updates with props, works as a stateless function and works with SSR such as next.js.
It even allows bypassing actions.order.create() so that you can call your own API's.
import { PayPalButton } from "react-paypal-button-v2";
const PaypalButton = ({total, cart}) => {
return (
<PayPalButton
createOrder={(data, actions) => {
return fetch('/api/paypal/create-transaction', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
total: total,
cart: cart,
})
})
.then((response) => {return response.json()})
.then((data) => {return data.orderID})
.catch(error => console.log(error))
}}
onApprove={(data) => {
// Capture the funds from the transaction
return fetch('/api/paypal/capture-transaction', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ orderID: data.orderID })
})
.then((res) => { return res.json() })
.then((details) => {
if(details === 200){
console.log('success');
} else {
console.log('failure');
}
})
.catch(error => {
console.log(error)
})
}}
options={{
clientId: process.env.PAYPAL_CLIENT_ID
}}
/>
);
}
export default PaypalButton;

How can I dynamically rerender my api to my webpage?

So I have this api and I am making a get request in my ComponentDidMount() to dynamically render it to my page and it works. The issue I am facing is when I make a post request to add items to the list, it does not show on my webpage unless I refresh it. The backend is my data.json so I don't know if that is the problem but essentially when I make a post request, I am adding data to my data.json and I want that to rerender on my page without me refreshing it.
componentDidMount() {
axios.get("/api/workboard")
.then(res => {
res.data["boardLists"].map((item, key) => {
// console.log(Object.keys(item)[0])
this.setState(prevState => ({
data: [...prevState.data, item],
titles: [...prevState.titles, Object.keys(item)[0]]
}))
})
// console.log(this.state.titles)
// console.log(this.state.data)
}).catch(err => console.log(err))
}
addListItemHandler = () => {
axios({
method: 'post',
url: 'api/workboard/0/list',
data: {
title: "Untitled" ,
description: "No Description"
}
})
.then(res => {
console.log(res)
})
.catch(err => console.log(err));
}
render() {
let board = this.state.data.map((item, key) => {
return <WorkBoardContainer
key={key}
title={item[this.state.titles[key]]["title"]}
listItems={item[this.state.titles[key]]["list"].map((i) => {
return i["title"]
})}
/>
})
return (
<div className={classes.App}>
<AddButton addListItemHandler={this.addListItemHandler}/>
{board}
</div>
);
}
Try moving the fetching part as a seperate function and call it again once the post request is done.
componentDidMount() {
// fetch data when component is mounted
this.fetchData();
}
fetchData = () => {
axios.get("/api/workboard")
.then(res => {
res.data["boardLists"].map((item, key) => {
this.setState(prevState => ({
data: [...prevState.data, item],
titles: [...prevState.titles, Object.keys(item)[0]]
}))
})
}).catch(err => console.log(err))
}
addListItemHandler = () => {
axios({
method: 'post',
url: 'api/workboard/0/list',
data: {
title: "Untitled" ,
description: "No Description"
}
})
.then(res => {
console.log(res);
// fetch data again once post is done.
this.fetchData();
})
.catch(err => console.log(err));
}

Resources