Initial state
super(props);
this.state = {
user: {
id: 0,
firstName: '',
lastName: '',
phoneNumbers: ['', '', ''],
}
};
}
my handleInputChange function:
handleInputChange = (event) => {
const { user } = this.state;
const name = event.target.name;
const value = event.target.value;
if (name === 'contactNumber1') {
user.phoneNumbers[0] = value;
} else if (name === 'contactNumber2') {
user.phoneNumbers[1] = value;
} else if (name === 'contactNumber3') {
user.phoneNumbers[2] = value;
console.log('hellooo', user.phoneNumbers);
} else {
user[name] = value;
}
const filteredPhoneNumbers = user.phoneNumbers.filter(e => e !== '');
this.setState(prevState => ({
user: {
...prevState.user,
[name]: value,
phoneNumbers: [...filteredPhoneNumbers],
},
}));
}
When I remove an element, the element in the index above populates the element I just deleted What am I missing?
* I am getting this error because of my code too - A component is changing a controlled input of type undefined to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component*
You could try parsing "this.state" like this:
const { user } = JSON.parse(JSON.stringify(this.state));
I think you're referencing the same object to the user cons
Related
The problem is that calling unCheckAllColums updates the data of the set state (configEdit, configNoEdit) and additionally updates the value that comes from the props, and it should only update the configEdit
export fuction HookConfigsUser(configUser){
const initValues = {
configEdit: configUser; // this value only edit
configNoEdit: configUser; // this value use to recover info
}
const [values, setValues] = useState(initValues)
const unCheckAllColums = () => {
let editValue = { ...configEdit,}
let setListEdit = editValue.config.map((conf) => {
if (conf.enableEditShow === false) {
conf.show = true
} else {
conf.show = false
}
return conf
})
editValue.config = setListEdit
editValue.isEdit = true
const toSetAllstate = {
...values,
configEdit: editValue,
}
setValues(toSetAlstate)
}
const recoverInfo(){
setValues({
...values,
configEdit: values.configNoEdit,
}) }
return [unCheckAllColums, recoverInfo]
}
When calling the function all the variables are updated, those that are in setstate and the props and only the value inside state called configEdit should be updated.
Here i want to update the state.value as i get data from the input and im using "name" tag to find what exactly key to be updated in the state.value. But here in my code im using useReducer hook to store data in state in my custom react hook useInput. but the problem im facing is i cannot udpate state here as you can see i am getting data from the dispatcher function but i cant save it to the state since i cannot access it from the reducer function.
import React from "react";
const reducer = (state, actions) => {
switch (actions.type) {
case "getData":
return {
...state,
value: { ...state.value, [actions.name]: actions.value }, // ****cannot acccess data here
};
default:
return state;
}
};
const useInput = () => {
const defaultValue = {
value: {
fullname: "",
address: "",
pincode: "",
city: "",
phone: "",
},
touch: {
fullname: false,
address: false,
pincode: false,
city: false,
phone: false,
},
};
const [state, dispatcher] = React.useReducer(reducer, defaultValue);
const getData = (e) => {
const name = e.target.name;
const value = e.target.value;
dispatcher({ type: "getData", [name]: value }); // ****heres the dispatcher function
};
// const blurHandler = (e) => {
// dispatcher({ type: "touch", value: true });
// };
console.log(state.value);
return {
getData,
};
};
export default useInput;
Try to pass a payload object containing a name and value property to the dispatch function:
const getData = (e) => {
const name = e.target.name;
const value = e.target.value;
dispatcher({ type: "getData", payload: { name, value }});
};
You can then modify your reducer like this to edit the relative value:
const reducer = (state, actions) => {
switch (actions.type) {
case "getData":
return {
...state,
value: { ...state.value, [actions.payload.name]: actions.payload.value },
};
default:
return state;
}
};
I've got two select components and I want to set values from this selectors to state using one handleChange method. I've tried to do like this:
handleChange = event => {
const { name, value } = event.target;
if (name === 'City') {
this.setState({ selectedCity: value });
} else if (name === 'Theatre') {
this.setState({ selectedTheatre: value });
}
};
But I want more universal solution, like I did with inputs:
handleChange = event => {
const { name, value } = event.target;
this.setState({
[name]: value
});
};
My state
this.state = {
cities: [],
theatres: [],
movies: [],
selectedCity: 1,
selectedTheatre: 1
};
at the first, the name for each input must look like the element in the state
ex
tell me
handaleChange=(event)=>{
this.setState({
[event.name]=event.target.value
}
}
tell me if it work or not
make Handel different for selected Combobox element different
handelSelectedElement=(event)=>{
const value=event.target.checked
const name:event.target.name;
let cityselected=Object.assign({},this.state.city,{[name]:value})
this.setState({city:cityselected})}
tell me if work or not
Ensure your dropdown list name matches the state name
this.state = {
cities: [],
theatres: [],
movies: [],
selectedCity: 1,
selectedTheatre: 1
};
<select name="selectedCity"
value={this.state.selectedCity}
onChange={this.handleChange }>
</select>
<select
name="selectedTheatre"
value={this.state.selectedTheatre}
onChange={this.handleChange }>
</select>
handleChange = event => {
const target = event.target
const value = target.type === 'checkbox' ? target.checked : target.value
const name = target.name
this.setState({
[name]: value
});
};
Note: Dont forget to copy your event data into a variable or call event.persist() to avoid issues.
See link [Event target is null inside functional setState
My parent component has a property in its state called formIsValid, initially set to false. My form also has a submit button. I want the submit button to be disabled until after some input fields (a first name and a last name input) have data in them.
This is what my state looks like:
state = {
employees: [],
costEstimates: emptyCosts(),
relationshipOptions: [],
newEmployee: emptyEmployee(),
formIsValid: false
};
This function handles changes to the First and Last name inputs:
// handle input into "First Name" and "Last Name" inputs
handleChangeValue = async e => {
const newEmployee = { ...this.state.newEmployee };
newEmployee[e.currentTarget.name] = e.currentTarget.value;
this.setState({ newEmployee });
this.validateIfCanBeSubmitted();
await this.updateCostsData(newEmployee); // this is an api thing, not relevent
};
This is what sets the formIsValid property in the state. This property is sent as a prop to the Submit button.
validateIfCanBeSubmitted = () => {
const { firstName, lastName } = this.state.newEmployee;
let formIsValid = firstName && lastName ? true : false;
this.setState({ formIsValid });
};
The Submit button for this is correctly getting disabled if the employee property in the state has its first and last names as empty. The problem is that it's "off by 1 update." It's as if the props aren't getting propagated down to the child button component until after the NEXT time the state changes. Here's a gif of the issue:
This is what the child component looks like. It's just a regular HTML button, however it's within a Stateless Functional Component, so the issue is not with the component's state:
<button
type="button"
onClick={onSubmit}
className={'btn btn-primary mr-1 ' + (formIsValid ? '' : 'disabled')}
disabled={!formIsValid}
>
setState() is asynchronous!
this.validateIfCanBeSubmitted(); is executed on the old state; this update this.setState({ newEmployee }); has not been propagated to this.state when your function is executed.
Make validateIfCanBeSubmitted an update-function.
validateIfCanBeSubmitted = ({ newEmployee: { firstName, lastName }}) => {
return {
formIsValid: firstName && lastName ? true : false
};
}
and use it accordingly:
handleChangeValue = async e => {
const {name, value} = e.currentTarget;
const newEmployee = {
...this.state.newEmployee,
[name]: value
};
this.setState({ newEmployee });
this.setState(this.validateIfCanBeSubmitted);
// this is an api thing, not relevant
await this.updateCostsData(newEmployee);
};
Actually, the code in handleChangeValue should also be in such a function, as it uses the previous state to compute the new one.
so how about combining them:
handleChangeValue = e => {
const {name, value} = e.currentTarget;
this.setState((state) => {
const newEmployee = {
...this.state.newEmployee,
[name]: value
};
const { firstName, lastName } = newEmployee;
const formIsValid = firstName && lastName ? true : false;
//and since you never use the returned Promise, why make anything async?
this.updateCostsData(newEmployee);
return { newEmployee, formIsValid };
});
};
What's the best way to update a nested property deep inside the State object?
// constructor --
this.state.someprop = [{quadrangle: {rectangle: {width: * }}, ...}]
...
I want to update width of the rectangle object.
this.state.quadrangle.rectangle.width = newvalue // isn't working
I could make it work like:
const {quadrangle} = this.state
quadrangle.rectangle.width = newvalue
this.setState = {
quadrangle: quadrangle
}
But this method doesn't sound the best way for performance/memory
// ES6 WAYS TO UPDATE STATE
// NOTE: you MUST use this.setState() function for updates to your state
class Example extends Component {
constructor(props) {
super(props);
this.state = {
name: 'John',
details: {
age: 28,
height: 1.79,
}
}
componentDidMount() {
this.handleChangeName('Snow');
this.handleAgeChange(30);
}
componentDidUpdate() {
console.log(this.state);
/*
returns
{
name: 'Snow',
details: {
age: 30,
height: 1.79,
}
}
*/
}
// this way you keep your previous state immutable (best practice) with
// param "prevState"
handleChangeName = (_name) => {
this.setState(
(prevState) => ({
name: _name
})
)
}
//this is how you update just one property from an internal object
handleAgeChange = (_age) => {
this.setState(
(prevState) => ({
details: Object.assign({}, prevState.details, {
age: _age
})
})
)
}
// this is the simplest way to set state
handleSimpleAgeChange = (_age) => {
this.setState({
details: Object.assign({}, this.state.details, { age: _age })
})
}
render() {
return (
<h1>My name is {this.state.name} and I'm {this.state.details.age} years old</h1>
)
}
}
If you want to keep the best practice without making it harder, you can do:
updateState = (obj) => {
if (obj instance of Object) {
this.setState(
(prevState) => (Object.assign({}, prevState, obj))
);
}
}
usage:
//code ... code ... code ...
handleAgeChange = (_age) => {
this.updateState({
details: Object.assign({}, this.state.details, { age: _age }
})
}
The best way, and the way facebook has proposed, is to use this.setState({someProp: "your new prop"}).
Using it is the only way which is going to guarantee that the component will be rendered correctly.
This function is incremental, so you dont need to set the whole state, just the prop you need.
I strongly recomend you to read the docs here.
If your object is nested make the inner object it's own state,
this.state = {
quadrangle: {this.state.rectangle, ...}
rectangle: {width: * }}
};
then use your clone and replace technique:
const {rectangleNew} = this.state.rectangle;
rectangleNew.width = newvalue;
this.setState({rectangle: rectangleNew});
The state should propagate upwards. Should improve performance if only certain quadrangles need to be updated based on said rectangle. Props down, state up.
with hooks use this way
- setBorder((pre) => { return ({ ...pre, border_3: 2 }) })
example :
// state for image selected [ borderd ]
const [bordered, setBorder] = useState({ border_1: 0, border_2: 0, border_3: 0, border_4: 0, border_5: 0, border_6: 0, border_7: 0, border_8: 0 });
// pre is previous state value
const handle_chose = (y) => {
//generate Dynamic Key
var key = "border_" + y;
setBorder((pre) => { return ({ ...pre, [key]: 2 }) })
}