I use Material-UI in order to create a DateTime picker. Here is my demo code.
I added console.log to the function handleChange in order to see a current selected value. However, the value does not change when I use DatTime picker:
handleChange = name => event => {
const target = event.target;
const name = target.name;
console.log("plannedDep", this.state.plannedDep)
this.setState({
[name]: event.target.value
});
};
I added the state value as default value to plannedDep. value={this.state.plannedDep}
I changed the onChange this way: onChange={(event) => this.handleChange("plannedDep", event)}. Going by your code, onChange={this.handleChange("plannedDep")} the onchange you have will be fired as soon as the component is mounted and for every state/prop change resulting in unnecessary renders.
<TextField
id="datetime-local"
label="Next appointment"
type="datetime-local"
onChange={(event) => this.handleChange("plannedDep", event)}
value={this.state.plannedDep}
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
/>
We have to check the value after setting the state, not before setting it. Im doing the check in the setState's callback, and it shows the updated value to me.
handleChange = (name, event) => {
const target = event.target; // Do we need this?(unused in the function scope)!
this.setState({
[name]: event.target.value
}, () => {
console.log(this.state.plannedDep)
// Prints the new value.
});
};
I hope this solves your problem :)
You override the name argument passed to the method handleChange inside that method, doing const name = target.name;, so when you set back the state at the end:
this.setState({
[name]: event.target.value
})
You are not setting the expected plannedDep.
You can fix it in two ways:
1) Set the state directly through:
this.setState({
plannedDep: event.target.value
})
2) Add a name attribute to your TextField so that target.name will be the value of the name attribute of your TextField which fired the event:
<TextField
id="datetime-local"
name="plannedDep" // see here!
label="Next appointment"
type="datetime-local"
onChange={this.handleChange("plannedDep")}
defaultValue="2017-05-24T10:30"
className={classes.textField}
InputLabelProps={{
shrink: true
}}
/>
Here the working demo
I believe the issue is your onChange handler. If you are passing a value into the onChange you must initialize it in a callback.
Try changing your onChange to onChange={() => this.handleChange("plannedDep")}
Related
I need to set like if the value of check box is coming true then check box show selected if the value comes false check box gets selected but what happening its value getting true from the backend I am storing value in the state rules but it's not getting enable and if the value is getting true also I am not able to check and unchecked checkbox when value is true checkbox not check when value it's true why it's happening not sure also I am trying to set onChange but getting confused how to set onchange
value coming from backend
NameMatch: true
Match: true
SearchForm component
export default function SearchForm() {
const { setRules, rules, fetchSearch } = useRule();
const [changeRuleSettings, setChangeRuleSettings] = React.useState(false);
React.useEffect(() => {
fetchSearchRule();
}, []);
const handleCheckBoxChange = (e) => {
setRules((prevRules) => ({
...prevRules,
[e.target.name]: !prevState[e.target.checked],
}));
};
return (
<Grid item xs={4}>
<Box className={classes.formText}>
<Checkbox
style={style}
name="NameMatch"
checked={rules.NameMatch}
color="primary"
onChange={handleCheckBoxChange}
/>
<Typography variant="subtitle2" noWrap={true}>
Match
</Typography>
</Box>
</Grid>
)
}
If I am understanding the question correctly, you are asking what should the onChange function exactly do. So basically you need to switch the values of the property, that the Checkbox is dependent on. For example, if the backend returns :
exactNameMatch: true
partialNameMatch: true
Then for the first checkbox, when it is clicked, the value of exactNameMatch should be set to false. An example implementation would look something like this:
onChange={(e) => setRules((prevRules) => ({...prevRules, exactNameMatch: !prevRules.exactNameMatch}))}
For the second checkbox the onChange will be identical, with the small difference, that instead of exactNameMatch you would use partialNameMatch.
Another possibility is to implement the handleCheckBoxChange function like so:
const handleCheckBoxChange = (e) => {
setRules((prevRules) => ({...prevRules, [e.target.name]: !prevRules[e.target.name]}))
}
Where e.target.name is respectively exactNameMatch or partialNameMatch, based on the values you have passed to the name properties of the Checkbox component. Hope I managed to understand your problem correctly and actually help you!
I have a functional component JobItem. In my parent container, I manage the state. Everything works fine except for the memoization because prevProps and nextProps attributes are always equal.
Here is my component:
function areEqual(prevProps, nextProps) {
console.log(prevProps.job_item.quantity)
console.log(nextProps.job_item.quantity)
return false
};
const JobItem = React.memo(props => {
return (
....
)
}, areEqual);
export default JobItem;
Here is my event handler:
handleItemChange = (item, event) => {
item[event.target.name] = event.target.value;
this.setState({
job: this.state.job
})
}
In my areEqual function, I must return false for the component to update because nextProps.job_item.quantity is always equal to prevProps.job_item.quantity. I assume this has something to do with my event handler but I am not sure how to fix this.
Here is an example of the quantity field that calls the handler by first passing an instance of the job_item and then the event itself which allows me to change the attribute quantity on the job item which is apart of the current state and then set the state to the currently modified state object. The state object contains a job which contains an array of items.
<TextField
name={name}
value={value}
label={label}
variant="outlined"
type="number"
onChange={e => handleItemChange(item, e)}
InputLabelProps={{
shrink: true,
}}
/>
you are changing the reference of the state when you are using this.setState()
if you know that job_item.quantity is always same.
check like this
JSON.stringfy(prevProps.job_item.quantity) === JSON.stringfy(nextProps.job_item.quantity)
I just want to get value from Radio component (checked or unchecked) in ui-semantic having following code:
componentDidMount() {
this.setState({
startDate: moment()
.subtract(30, 'days')
.startOf('day'),
endDate: moment().endOf('day'),
isChecked: false,
});
}
Radio component:
<Radio toggle className="ongoing-checkbox"
label="Show ongoing alerts"
value={ !this.state.isChecked }
onChange={e => this.selectOngoingAlerts(e)}></Radio>
and handler function:
selectOngoingAlerts = (e) => {
this.setState(this.state.isChecked = true);
const { householdAlerts } = this.props;
console.log('checked', this.state.isChecked);
}
How to have a state of Radio component in selectOngoingAlerts function? I want to make different actions with respect whether radio is checked or unchecked.
You need to accept the data / checked value from the second argument of the onChange callback. You were trying to assign the value in setState as well which is wrong. do it like you do in your componentDidMount
selectOngoingAlerts = (e, data) => {
this.setState({isChecked: data});
}
Also update the radio component to just pass the callback to your handler, you dont need or want a lambda here..
<Radio toggle className="ongoing-checkbox"
label="Show ongoing alerts"
value={ !this.state.isChecked }
onChange={this.selectOngoingAlerts} />
From the docs, the second argument is where the value is passed
You should be referencing the Checkbox docs like I linked because the Radio is syntactic sugar for <Checkbox radio />
Remember: setState is async, so you cannot console.log the value like you are trying to. Instead use a callback on setState if you really want to see its updated value, or just move your console.log to the render so you can see the value change on render cycles.
selectOngoingAlerts = (e) => {
const {isChecked} = this.state;
this.setState({ isChecked : !isChecked });
isChecked ? console.log('on') : console.log('off');
}
So I am having trouble with setting the state for the date selected from this DatePicker
change:
change = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
DatePicker component:
<DatePicker
selected={this.state.startDate}
onChange={e => this.change(e)}
/>
If I use the default date when you first reload the page, there is no issue. But it's when a date is selected that I get an error.
A Type Error: Cannot read property 'name' of undefined.
What am I doing wrong?
The SyntheticEvent is pooled. This means that the SyntheticEvent object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons. As such, you cannot access the event in an asynchronous way.
More information can be found here.
Since setState is asynchronous the event will be null by the time it's evaluated in setState.
Instead, deconstruct the event before setState:
change = ({ target: { name, value } }) => {
this.setState({
[name]: value,
});
}
or
change = e => {
const { name, value } = e.target;
this.setState({
[name]: value,
});
}
How to write a generic function with various state variable change based on the dropdown.
for ex:
I have dropdown 1 and dropdown 2. If I change the
dropdown 1, I need to change the few state variables like a, b, c
dropdown 2, I need to change the few state variables like x, y, z
I can do this with 2 functions. But how to write a a generic function for this?
handleChange: function(e) {
//api call to xyz.com/getcompany/<company id> to get the job list here
this.setState({
selectedCompany: e.target.value,
companychange: "company changed. New value: " + e.target.value
})
},
handleChange2: function (e) {
// api call to xyz.com/jobstatus/<job id> to get the job status\(like how many position available for this job\) here
this.setState({
jobchange:"job changed. New value " + e.target.value
})
}
Codepen: https://codepen.io/asdhanapal/pen/WmwJPj?editors=0011
You could use a curried function to simplify the code a bit:
changeToState(fn) {
return e => this.setState(fn(e));
}
render() {
//...
<input onChange={changeToState(e => ({ selectedCompany: e.target.value, /*...*/ }))} />
<input onChange={changeToState(e => ({ jobChange: e.target.value, /*...*/ }))} />
}
If that is still to much boilerplate, you could extract the handleChange event into a functional component:
const StateChanger = ({ action, parent, ...props }) => (
<input onChange={e => parent.setState(action(e))} {...props} />
);
// inside a component's render:
<StateChanger parent={this} action={e => ({ selectedCompany: e.target.value })} style={{ color: red }} />
but as I already mentioned in the comments, that might remove repeated code a bit, but it doesn't improve readability / maintainability whatsoever.
You can use below snippet:
handleChange = event => {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
};
Reference to react docs section:
https://reactjs.org/docs/forms.html#handling-multiple-inputs
You can use following:
handleChange = event => {
const { name, value } = event.target;
this.setState({
[name]:value
})
}
// in input
<input name="username" onChange={this.handleChange} />
Try this:
handleChange: function(source, e) {
switch(source) {
case 'company':
//Need to do api call to get the job list here
this.setState({
selectedCompany: e.target.value,
companychange: "company changed. New value: " + e.target.value
})
break;
case 'job':
// Need to do api call to get the job status\(like how many position available for this job\) here
this.setState({
jobchange:"job changed. New value " + e.target.value
})
break;
};
},
<select value={this.state.selectedCompany} onChange={this.handleChange.bind(this, 'company')}>
<select value={this.state.selectedCompany} onChange={this.handleChange.bind(this, 'job')}>
As I read your description of the requirements, there are no functional dependencies between dropdown 1 and dropdown 2, so I'd split this up in two separate components.