Reputation: 177
UPDATE: I have logged three lines of code, before sending the data to updateEvent function containing the endpoint. The following is the logs:
the new event date is 2019-01-01T01:00:00.000
the new SET event date is: 2019-01-01T01:00
the event detail is: {date: "2019-01-01T01:00" …}
The state is once again not set to the new format. Can anyone see what the error could be?
I am trying to render an event date to send as body to an endpoint.The user is able to input the date in the TextInput field, however before I send the event date, I want to modify its format, using moment.js inside updateEvent cb (YYYY-MM-DDTkk:mm:ss.SSS"), therefore I create a new variable
newDate
However, the setState inside of updateEvent doesn't actually set state and keeps the value of date as it is has been set in handleEventInputChange. I have a suspicion that it could be due to setting state to the same state variable twice, inside the handleEventInputChange and handleEvent. Can anyone confirm and/or propose a solution?
//... import and styles
class EditEvent extends Component {
constructor(props) {
super(props);
this.state = {
event: {
date: '',
},
};
this.handleEventInputChange = this.handleEventInputChange.bind(this);
this.updateEvent = this.updateEvent.bind(this);
}
handleEventInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
event: {
...this.state.event,
[name]: value
}
});
}
updateEvent() {
const { event } = this.state;
let newDate = moment(this.state.event.date).format("YYYY-MM-DDTkk:mm:ss.SSS");
this.setState(() => ({
event: {
...this.state.event,
date: newDate,
}}))
console.log("the new event date is ", newDate)
console.log("the new SET event date is: ", event.date)
console.log("the event detail is: ", event)
this.props.updateEvent(this.props.event.id, event);
}
renderEvent() {
const {
event,
} = this.state;
return (
<div>
<Paper style={styles.paper}>
<TextField
name="date"
type="datetime-local"
onChange={this.handleEventInputChange}
value={event.date}/>
</Paper>
</div>
);
}
render() {
return (
<ViewContainer
title="Update Event"
toolbarRight={
<Button
onClick={this.updateEvent}
> Save
</Button>
}
>
{this.renderEvent()}
</ViewContainer>
);
}
}
//... mapStateToProps, mapDispatchToProps and export default connect for EditEvent
Upvotes: 1
Views: 5786
Reputation: 4068
This is a repost, the original answer is here:
From React's documentation (at the moment of this post)
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.
So no, your approach will not get the updated value from this.state
right away after calling setState
, and you cannot catch the updated value in console.log
for the same reason. According to the document, a better way is using componentDidUpdate
componentDidUpdate(prevProps, prevState) {
if (this.event.date !== prevState.event.date) {
this.props.updateEvent(this.props.event.id, event);
}
}
updateEvent() {
const { event } = this.state;
let newDate = moment(this.state.event.date).format("YYYY-MM-DDTkk:mm:ss.SSS");
this.setState(() => ({
event: {
...this.state.event,
date: newDate,
}}))
}
If you still insist on keeping this.props.updateEvent
inside updateEvent
then there are 2 ways of doing it:
(1) Use newDate
instead of this.state.event.date
updateEvent() {
const { event } = this.state;
let newDate = moment(this.state.event.date).format("YYYY-MM-DDTkk:mm:ss.SSS");
this.setState(() => ({
event: {
...this.state.event,
date: newDate,
}}))
this.props.updateEvent(this.props.event.id, {
...this.state.event,
date: newDate
});
}
or (2) using callback of this.setState
to correctly get updated value
updateEvent() {
const { event } = this.state;
let newDate = moment(this.state.event.date).format("YYYY-MM-DDTkk:mm:ss.SSS");
this.setState(() => ({
event: {
...this.state.event,
date: newDate,
}}),
function callback() {
this.props.updateEvent(this.props.event.id, this.state.event);
}
)
}
Upvotes: 1
Reputation: 38757
Based on the code you provided, you are attempting to set [name]: value
inside setState()
of handler handleEventInputChange(event)
, but you haven't set assigned a value from event
argument to the value
property. You'd need to add something along the lines of const value = target.value;
before passing it to setState()
:
handleEventInputChange(event) {
const target = event.target;
const name = target.name;
const value = target.value; // add this
this.setState({
event: {
...this.state.event,
[name]: value
}
});
}
You could also consider using destructuring:
handleEventInputChange(event) {
const target = event.target;
const { name, value } = target;
this.setState({
event: {
...this.state.event,
[name]: value
}
});
}
Update: onChange
for an <input type="datetime-local" />
will only fire when all parts of the <input type="datetime-local" />
have been filled in including day, month, year, hour, minute and AM/PM. I've creating an example showing this functionality in action. Your code with the change to setting the value of value
seems to work. If the goal is to always show the formatted date, you could consider creating another state property the holds the formatted value to avoid changing this.state.event.date
when updateEvent()
is triggered by the button click. This way you can avoid overwriting this.state.event.date
constantly.
Update 2: Based on the comments, I'm piecing together that issue you are trying to resolve specifically is the value that is being passed to a mapped action dispatch. You could try using the setState()
callback, 2nd argument, to call this.props.updateEvent()
. It's key that you pass this.event.state
into the 2nd argument of this.props.updateEvent()
otherwise you would be passing the old/original event value. The example has been updated to reflect this.
updateEvent() {
const { event } = this.state;
let newDate = moment(this.state.event.date).format("YYYY-MM-DDTkk:mm:ss.SSS");
this.setState({
event: {
...this.state.event,
date: newDate,
}
}, () => {
this.props.updateEvent(this.props.event.id, this.state.event);
});
}
Hopefully that helps!
Upvotes: 3