I need to declare a variable for formstate.title from this:
const initialState = { description: '', place: "", date: "", membersJoinedCounter: 0, title: "" };
const [formState, setFormState] = useState(initialState);
function setInput(key, value,) {
setFormState({ ...formState, [key]: value })
}
const userTitle = await API.graphql(graphqlOperation(getUserTitle, {id: userInfo.attributes.sub}))
formState.title = userTitle.data.getUser.title;
How to achieve that?
it's not clear what you wanted to ask, but assuming you want to set title value after fetching data, you can achieve that via using setFormstate method provided by useState hook (you can't directly set values as formstate returned by useState hook is immutable)
replace below line in your code
formState.title = userTitle.data.getUser.title
with below one
setFormState(prev=>({...prev,title:userTitle.data.getUser.title}))
Related
I'm trying to save objects to an array, but I can't do it, the old state is deleted. I have two states in my component, from two different forms, the first form is just text and I get the data by "handleChange", but the second form is several objects that I want to store in an array that I get by "handleChangeArray".
const [formCompra, setFormCompra] = useState({
name: '',
lastName: '',
items: []
});
const [restForm, setRestForm] = useState();
const handleChage = (e) => {
const { name, value } = e.target;
setFormCompra({
...formCompra,
[name]: value
})
}
const handleChangeArray = (e) => {
const { name, value } = e.target;
setRestForm({
...restForm,
[name]: value
})
}
const handleSubmit = () => {
let newData = {
name: formCompra.name,
lastName: formCompra.lastName,
items: [...formCompra.items, restForm] //probably the error is here
}
console.log(newData)
}
As I mention, it is not possible to save the data in the array, I appreciate any help.
You can use the current state to set a new value, keeping all other values:
setState((current) => ({
...current,
key: newValue
}));
I think the issue may be that spread syntax only shallow copies the array, so in
const handleSubmit = () => {
let newData = {
name: formCompra.name,
lastName: formCompra.lastName,
items: [...formCompra.items, restForm] //probably the error is here
}
items is a copy of an array that points to all the original objects.
try
let newData = {
name: formCompra.name,
lastName: formCompra.lastName,
items: [...formCompra.map(x=>{...x}), {...restForm}] //probably the error is here
}
**I have a billing form and in this i have some product details that admin can fill these details but 1 field called "BillID" i want to directly pass a variable to it that contain 'Bill ID + 1' value as a default value.
**This is My Code:-
const [BillIdFetch, setBillIdFetch] = useState();
useEffect(() => {
axios.get("http://localhost:5000/getLastBill_Id").then(( res ) => {
setBillIdFetch(res.data[0].Bill_Id + 1);
});
}, []);
console.log("===>>>> Testing BillIdFetch ",BillIdFetch) //**I check in this variable value stored perfectly.
const [Product_Details, setProduct_Details] = useState([
{
index: Math.random(),
billId : BillIdFetch, //**I want 'BllIdFetch' value pass to this state variable.
prodId: "",
qty: "",
price: "",
prod_SrNo: "",
discount_price: "",
proData_warranty: "",
},
]);
In 'BillIdFetch' i got correct id + 1 value and i also use this value for displaying Bill no. in form column. but when i set this value to 'billId' it shows like this :- {billId: undefined}
This is post request to the server.
In this a pass 'Produt_Details' array of object to it.
const config = {
header: {
"Content type": "appication/json",
},
};
const { data } = await axios.post(
"http://localhost:5000/billing_data",
{ p_value: Product_Details },
config
);
What you need to do is to check when BillIdFetch changes, and then set the correct state value for Product_Details. In your current code, the code for setting the value of Product_Details? will run before the fetching.
To solve this, use a useEffect hook with BillIdFetch as a dependency, thus, this code will run when BillIdFetch changes.
It could look something like this:
const [Product_Details, setProduct_Details] = useState([]);
const [BillIdFetch, setBillIdFetch] = useState();
useEffect(() => {
axios.get("http://localhost:5000/getLastBill_Id").then(( res ) => {
setBillIdFetch(res.data[0].Bill_Id + 1);
});
}, []);
useEffect(() => {
if (billIdFetch === undefined) return;
setProduct_Details([{
index: Math.random(),
billId : BillIdFetch,
prodId: "",
qty: "",
price: "",
prod_SrNo: "",
discount_price: "",
proData_warranty: "",
}])
}, [billIdFetch])
I have my state like
this.state = {
data: [],
dataloaded: false,
isopen: false,
firstname: '',
lastname:'',
email:'',
gender: '',
avatar: '',
number:'',
dob:new Date()
};
And I am having form to update state,
every text input has onchange such as this onChange={this.handleOnChange("firstname")}
And my hndleOnChange function is:
handleOnChange = field => event => {
console.log(event.target.value,field)
this.setState({field: event.target.value})
}
this doesnt work
This is not updating the state
but if i do
handleOnChange = field => event => {
console.log(event.target.value,field)
this.setState({[field]: event.target.value})
}
this works
Why does adding bracket infront of objectname it gets correct?
Adding brackets means the value of that variable becomes the object key. Without brackets, the literal name becomes the object key. As an example:
const key = "name";
const object = {
key: "My Key",
name: "My Name"
};
obj.key // "My Key"
obj[key] // "My Name" -> equivalent to obj["name"] or object.name
Check out MDN's Working with Objects for more information.
In you case, this code:
handleOnChange = field => event => {
console.log(event.target.value,field)
this.setState({field: event.target.value})
}
is trying to set a state property named field, instead of the state property associated with the value of the field variable.
I have this code in my constructor:
this.state = {
tests: [
{
question: "1",
answer: "2",
user: ""
},
{
question: "1",
answer: "2",
user: ""
},
],
};
I have edit function where I read event value in my input:
edit(id, event) {
this.state.tests[id].user = event.target.value;
this.setState({tests:this.state.tests});
}
But es give me this warning:
Do not mutate state directly. Use setState()
react/no-direct-mutation-state
What can i do in this case? Maybe somehow change the line with the assignment event.target.value into setState()?
You can use map() to create copy of tests
edit(id, event) {
const user = event.target.value;
const tests = this.state.tests.map((x,i) => i === id ? {...x, user} : x);
this.setState({tests});
}
One way I tend to go is to make a copy of the array first and then change an item in it, or change the array itself, and then set the state
var tests = this.state.tests.slice(0);
tests[id].user = event.target.value;
this.setState({tests:tests});
You may want to deep-clone the array in some cases, sometimes not.
You are correct, that the problem is with the line:
this.state.tests[id].user = event.target.value;
That's the point where you are mutating your state directly.
You have a few options.
You can "clone" the array first and then update it:
const newTests = [...this.state.tests];
newTests[id].user = event.target.value;
this.setState({tests: newTests});
You could also use immutability-helper:
const {value} = event.target;
this.setState(prevState => update(prevState, {[id]: {user: {$set: value}}}));
In this example, you need to extract value from your event, because it's not safe to access event values in asynchronous calls after an event has been handled.
edit(id, event) {
var newNote = {...this.state.tests[id]}
newNote.user = event.target.value
this.setState({ tests: [...this.state.tests, newNote]})
}
First of all, when you try to set a the new state using the data from previous state you have to use the updater as a function
https://reactjs.org/docs/react-component.html#setstate
const edit = (id, event) => {
this.setState((prevState) => {
const tests = [...prevState.tests];
tests[id] = {
...tests[id],
user: event.target.value
};
return {
...prevState,
tests
};
});
};
When state is not heavy, I use the following codes:
edit (id, event) {
const cp = JSON.parse(JSON.stringify(this.state.tests))
cp[id].user = event.target.value
this.setState({ tests: cp })
}
Update: I found Immer solves it perfectly.
import produce from 'immer'
edit (id, event) {
this.setState(
produce(draft => draft.tests[id].user = event.target.value)
)
}
I have a state object that looks like this.
this.state = {
formValues: {},
};
After some processing, formValues contains the following.
this.state = {
formValues: {
q1: value 1,
q2: value 2
},
};
Now i have q3 inside formValues which is an array of values. When i try to push the value like as follows
let q3 = e.target.name,
arrayValues = [1,2,3]
formValues[q3].push(arrayValues)
I am getting the following error while submitting the data
Uncaught Error: A state mutation was detected between dispatches
It looks like there is a problem with pushing data into array. Any idea on how to fix this?
You need to create a copy and update the state with setState instead of direct state mutation with push.
this.setState(prevState => ({
formValues: {
...prevState.formValues,
[q3]: prevState.formValues[q3].concat(arrayValues),
},
}));
assuming that you always want to push to your array such as in your use case:
const { formValues } = this.state
const arrayValues = [1,2,4]
const newFormValues = { ...formValues, q3: [...formValues[q3], arrayValues]}
this.setState({ formValues: newFormValues })
but much better if you control directly the value of q3:
const { formValues } = this.state
const arrayValues = [1,2,4]
const newFormValues = { ...formValues, q3: arrayValues}
this.setState({ formValues: newFormValues })