Hello I am newer at react but I am getting an error when I am trying to POST and I think that it is my changeHandler Wondering if someone can see something that I don't.
import React, {Component} from 'react'
import axios from 'axios'
class Form extends Component{
constructor(props) {
super(props)
this.state = {
appointment:{
customer_first_name: "",
customer_last_name: "",
date: "",
email: "",
notes: "",
phone: "",
time: ""
}
}
}
changeHandler = e => {
var appointment = { ...this.state.appointment };
appointment.[e.target.name] = e.target.value;
this.setState({appointment})
}
submitHandler = e => {
e.preventDefault()
console.log(this.state)
axios
.post('test/api', this.state.appointment)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
There is a syntactical error in your changeHandler. If you are using the bracket notation, then you do not use a dot:
// wrong
appointment.[e.target.name] = e.target.value;
// right
appointment[e.target.name] = e.target.value;
Besides, you can combine the deconstruction and assignment operation as follows:
changeHandler = e => {
var appointment = { ...this.state.appointment, [e.target.name]: e.target.value };
this.setState({appointment})
}
Note that because the assignment comes after the deconstruction, if a variable with the same name already exists, it is overwritten by the new value as set by [e.target.name]: e.target.value.
Related
I try call request post with hooks. Firstly, a call request post using this.setState and it working correctly
but I want to use a hook (useState) instead of setState and it doesn't work
code below working correctly
export default class AddShoes extends Component {
constructor(props) {
super(props);
this.state = this.startValue;
this.state.show = false;
this.shoesChange = this.shoesChange.bind(this);
}
startValue = {
brand: "",
model: "",
date: "",
price: "",
img: "",
};
shoesChange = (event) => {
this.setState({
[event.target.name]: event.target.value,
});
};
submitShoes = (event) => {
event.preventDefault();
const shoes = {
brand: this.state.brand,
model: this.state.model,
date: this.state.date,
price: this.state.price,
img: this.state.img,
};
axios.post("http://localhost:8080/api", shoes).then((response) => {
if (response.data != null) {
this.setState(this.startValue);
alert("added")
}
});
};
the second code below doesn't work
export default function AddShoes() {
const [values, setValues] = useState({
brand: "",
model: "",
date: "",
price: "",
img: "",
});
// const [show, setShow] = useState(false);
const handleSetInputs = (e) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
const submitShoes = (event) => {
event.preventDefault();
axios.post("http://localhost:8080/api", values)
.then((response) => {
if (response.data != null) {
setValues(response.data);
alert("added!");
}
});
};
what I should change?
To just change one property from an state-object in React Hooks you have to do this:
setValues(prevValues => ({ ...prevValues, [e.target.name]: e.target.value }));
In the first example that works, you are resetting the state by calling this.setState(this.startValue)
In the second example, you are passing the result of the network request inside setValue setValues(response.data)
Create initialValues outside of AddShoes function component.
const initialValues = {
brand: "",
model: "",
date: "",
price: "",
img: "",
}
Now pass that into setValues inside submitShoes
const submitShoes = (event) => {
event.preventDefault();
axios.post("http://localhost:8080/api", values)
.then((response) => {
if (response.data != null) {
setValues(initialValues);
alert("added!");
}
});
};
I'm struggling to get my data from a fetch request into the state of my container
My fetch request is stored in api.js and looks like this - it retrieves the key from a constant which is fine:-
import { openWeatherKey } from './constants';
const getWeather = async() => {
const base = "https://api.openweathermap.org/data/2.5/onecall";
const query = `?lat=52.6&lon=-2.2&exclude=hourly,daily&appid=${openWeatherKey}`;
const response = await fetch(base + query);
const data = await response.json();
return data;
}
export { getWeather };
My container looks like this:-
import React, { Component } from "react";
import './weather.css';
import { getWeather } from './api';
class Spy extends Component {
constructor() {
super()
this.state = {test(){return "this is a test"}}
}
render() {
return (
<div id="spy-weather" className="app-border">
<h3 className="spy-name">Weather at { this.props.location } {this.state.test()}</h3>
</div>
)
}
}
(() => {
getWeather().then(data => {
console.log(data);
})
})();
export { Spy as Weather };
I have an IIFE which makes the request and prints the results to the console. You can see that between the class declaration and the export statement above.
Here are the results from the console - the request works fine
{lat: 52.6, lon: -2.2, timezone: "Europe/London", timezone_offset: 3600, current: {…}}
current: {dt: 1594401262, sunrise: 1594353486, sunset: 1594412995, temp: 289.05, feels_like: 286.49, …}
lat: 52.6
lon: -2.2
timezone: "Europe/London"
timezone_offset: 3600
__proto__: Object
What I can't manage to do is set the state with the data from the resolved promise. I've tried various things, including some solutions I've seen which didn't work.
How do I place and run the function within the container and then update state with the data?
I'm pretty new to React as you can probably tell.
With sincere thanks,
Phil
In class based components, lifecycle method known as componentDidMount is used to do something after component has mounted. In your case, move the code in IIFE in the componentDidMount method.
Make a property in state object which will hold the weather data. Optionally, you can also make a property in state object to hold any error message that might occur during the fetching of data from the API.
this.state = {
weatherData: null,
error: ''
};
and then call getWeather() function from componentDidMount() lifecycle method
componentDidMount() {
getWeather()
.then(data => {
this.setState({ weatherData: data });
})
.catch(error => this.setState({ error: error.message }));
}
In functional components, useEffect hook is used to perform any side-effect like fetching data from an API. State in functional components is saved using useState hook.
If you use a functional component, then your code will look like this:
const [weatherData, setWeatherData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
getWeather()
.then(data => {
setWeatherData(data);
})
.catch(error => setError(error.message));
}, []);
this.state = {test(){return "this is a test"}}
This is invalid structure for state managment, right way
getWeather().then(data => {
console.log(data);
this.setState({ weatherData: data });
})
state structure too
state = {
someProperty: value,
someArray: [],
weatherData: {}
}
These are my states using hooks:
const [adminProfile, setProfile] = useState({
locations: [],
});
const [location, setLocation] = useState({
locationName: "",
location: {},
locationPhone: "",
locationEmail: "",
staff: [],
multipleKitchens: false,
kitchens: [],
});
const [locationList, setLocationList] = useState([]);
const [locationAddress, setAddress] = useState({
streetAddress: "",
streetAddress2: "",
city: "",
state: "",
zip: "",
country: "USA"
});
I have a bunch of fields with onChange handlers and an onClick handler that needs to update 3 states in order. First, LocationAddress has to become the state of the location property within the location state. Second, the location state has to be updated with a unique ID, and then that unique ID is inserted into the array in the locationList state. Finally, the entire array from locationList state is added to the locations property of adminProfile state. These are all in one component.
const handleClickLocation = () => {
setLocation(prevValue => ({
...prevValue,
locationID: uuidv4(),
location: locationAddress
}));
setLocationList(prevValue => [...prevValue, location.locationID]);
setProfile(prevValue => ({
...prevValue,
locations: locationList
}))
The first time the click handler is triggered, it sets only the first state in the handler and sends "undefined" into the second state. When the click handler is clicked a second time, it then behaves normally. I want all the states to update simultaneously. I've tried forceUpdate(), but couldn't figure out the syntax. I've tried using ReactDOM.unstable_batchedUpdates but it still behaved the same.
How can I get this to work? I want to keep this within one component. Is that possible?
Here is the entire code updated with the useEffect hook:
import React, {useState, useEffect} from "react";
import axios from "axios";
const { v4: uuidv4 } = require('uuid');
const CompanyProfileInfo = (props) => {
const todayDate = () => {
let today = new Date();
let day = today.getDate();
let month = today.getMonth() + 1;
let year = today.getFullYear();
if (day < 10) day = '0' + day;
if(month < 10) month = '0' + month;
return (month + "/" + day + "/" + year);
}
const [adminProfile, setProfile] = useState({
companyID: props.companyInfo.companyID,
firstName: "",
lastName: "",
phonePrimary: "",
phoneSecondary: "",
emailSecondary: "",
streetAddress: "",
streetAddress2: "",
city: "",
state: "",
zip: "",
country: "USA",
multipleLocations: false,
locations: [],
membershipLevel: "Basic",
joinedDate: todayDate(),
});
const [location, setLocation] = useState({
locationName: "",
locationPhone: "",
locationEmail: "",
staff: [],
multipleKitchens: false,
kitchens: [],
});
const [locationAddress, setAddress] = useState({
streetAddress: "",
streetAddress2: "",
city: "",
state: "",
zip: "",
country: "USA"
});
const [locationList, setLocationList] = useState([]);
useEffect(() => {
setLocationList(prevValue => [...prevValue, location.locationID]);
}, [location.locationID]);
useEffect(() => {
if (locationList[0] === undefined) {
{locationList.shift()}
}
setProfile(prevValue => ({
...prevValue,
locations: locationList
})
)
}, [locationList])
const handleChange = (event) => {
const {name, value} = event.target;
setProfile(prevValue => ({
...prevValue,
[name]: value
}))
}
const handleChangeLocations = (event) => {
const {name, value} = event.target;
setLocation(prevValue => ({
...prevValue,
[name]: value
}));
};
const handleChangeLocations1 = (event) => {
const {name, value} = event.target;
setAddress(prevValue => ({
...prevValue,
[name]: value
}));
};
const handleClickLocation = () => {
setLocation(prevValue => ({
...prevValue,
locationID: uuidv4(),
location: locationAddress,
}));
};
const handleClick = () => {
axios.post('http://localhost:3001/profileinfo', adminProfile)
.then(res => {
props.supportFunctions.setUpLocations(res);
})
.catch(function (error) {
console.log(error);
})
}
return (
<div>
</div>
)
}
export default CompanyProfileInfo;
setState is asynchronous, it means that when it is called, its state won't update at the same time, it takes some time to perform its action.
You can make use of useEffect to do that.
useEffect will perform an action only when the specified state (inside brackets) changes
useEffect(() => {
setLocation({
...location,
location: locationAddress,
locationID: uuidv4()
})
}, [locationAddress]) //When locationAddress changes, setLocation
useEffect(() => {
setLocationList([
...locationList,
location.locationID
])
}, [location]) //When location changes, insert Id
Ps: You can have multiple useEffects in your code.
Updating of the state is asynchronous behavior, because of that you are getting locationID undefined for setLocationList.
Inside class component, we can use a callback to setState call like this -
this.setState({ data: newData }, () => { console.log("This will get printed after setState") })
But in your case, you are using function component so you have to use useEffect react hook to listen for changes in your data and then update other data in the state.
Take a look at this question - How to use `setState` callback on react hooks
constructor(props) {
super(props)
this.state = {
isEdit: false,
currentProduct : {
sku: '',
productName: '',
description: '',
duration: '',
},
}
}
handleChange = (e) => {
this.setState({
currentProduct: {
...this.state.currentProduct,
[e.target.name]: e.target.value
}
})
}
clickHandle = (e) => {
e.preventDefault()
const currentProduct = {...this.state.currentProduct}
currentProduct.id = this.props.match.params.id
this.props.updateProduct(currentProduct)
this.props.history.push('/')
}
When updating field it updates the values but when i goes again to update single value it update only that and removes the other don't know why
handleChange = (e) => {
this.setState({
...this.state.currentProduct,
[e.target.name]: e.target.value
})
}
you are not destructuring entire state first. so do ...state. otherwise isEdit field will be lost.
handleChange = e => {
this.setState({
...this.state,
currentProduct: {
...this.state.currentProduct,
[e.target.name]: e.target.value
}
});
};
I'm trying to create a random quote machine with react hooks and I can code a list of them to appear, but I'm confused as to how to add steps to the useEffect function to get only one random one to show up.
I was able to list out each quote by mapping over them, but I don't know where in useEffect to have it pick only one quote and display it. I know how to code it for a class component, but how would I update this to reflect react hooks.
class RandomQuote extends Component {
constructor(props) {
super(props)
this.state = {
quote: '',
author: ''
}
}
componentDidMount() {
this.getQuote()
}
getQuote() {
let url =
'https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json'
axios.get(url)
.then(res => {
let data = res.data.quotes
let quoteNum = Math.floor(Math.random() * data.length)
let randomQuote = data[quoteNum]
this.setState({
quote: randomQuote['quote'],
author: randomQuote['author']
})
})
}
getNewQuote = () => { //will be called on clicking the New Quote button
this.getQuote()
}
const [data, setData] = useState({ quotes: [
{quote: '', author: ''}
] });
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json',
);
setData(result.data);
};
fetchData();
}, []);
I just need help 'translating' from and old React to the new hooks.
This is the full "translation" to React Hooks:
import { useCallback, useEffect, useState } from "react";
const RandomQuote = props => {
const [quote, setQuote] = useState("");
const [author, setAuthor] = useState("");
function getQuote() {
const url =
"https://gist.githubusercontent.com/camperbot/5a022b72e96c4c9585c32bf6a75f62d9/raw/e3c6895ce42069f0ee7e991229064f167fe8ccdc/quotes.json";
axios.get(url).then(res => {
const data = res.data.quotes;
const quoteNum = Math.floor(Math.random() * data.length);
const randomQuote = data[quoteNum];
setQuote(randomQuote.quote);
setAuthor(randomQuote.author);
});
}
useEffect(() => {
getQuote();
}, []);
const onButtonClick = useCallback(event => {
getQuote();
}, []);
return <button onClick={onButtonClick} />;
};