React Datepicker input state not changing? - reactjs

I have a multi-step form with child form components. On one of the components, I'm trying to implement YouCanBookMe DatePicker.
Now, when I try to update the state of datepicker's value like I do with other regular text inputs, the state does not get updated. If I typed the date, the state gets updated, but not when I actually select the date from the picker. I'm really clueless why. Can any of you point out why it doesn't?
Your help is greatly appreciated. I'm new to React and I've tried 3 different Datepicker libraries and I'm slowly going insane, because none seems to work or I'm not able to transform it to a Parent-Child structure. Thanks!
Parent:
constructor(props) {
super(props);
this.state = {
wants_interview_date: moment().format("DD-MM-YYYY")
}
}
handleChange(field) {
return (evt) => this.setState({ [field]: evt.target.value });
}
render(){
return <FormStep8
wants_interview_date={this.state.wants_interview_date}
onDateChange={this.handleChange('wants_interview_date')} />;
}
Child Component:
render() {
<Datetime
timeFormat={false}
dateFormat="DD-MM-YYYY"
inputProps={{id: 'wants_interview_date', onBlur: this.props.onDateChange, value: this.props.wants_interview_date}} //To get the regular HTML input props
/>
}

The good friends at Reactiflux helped me solve the issue. Apparently Moment.js was returning an Object on handleChange and therefore the state was not showing anything. The output needed to use the _d Moment.js method. Here is the correct handleChange method:
handleDateChange(field) {
return evt => {
const value = evt._d;
this.setState({ wants_interview_date: value });
};
}

this code snippet works fine for me, import DateTime (capital T)
import DateTime from 'react-datetime';
<DateTime name="newapp_time"
onChange={(e) => { this.setState({ newapp_time: moment(e).toJSON() }) }} />
the result is a timestamp in this case

Related

Working with multiple DatePickers in React Native Application

I am new to React Native but have been searching for days so if this is easy please let me off the hook.
I have this component:
<DatePicker
signInDate={this.state.signInDate}
mode="date"
placeholder="select date"
format="DD-MM-YYYY"
minDate="01-01-1950"
maxDate="01-01-2050"
androidMode="spinner"
showIcon={false}
onDateChange={this.onDateChange('signInDate')}
/>
Which uses this class:
export default class CPT extends Component {
constructor(props) {
super(props);
this.state = {
userName: '',
isModalVisible: false,
signInDate: "01-01-2000",
startPump: "01-01-2000",
endPump: "01-01-2000",
signOut: "01-01-2000",
equipmentUsed: '',
}
}
onDateChange = (state) => (event, value) => {
this.setState({
state: value });
}
Whenever I update the date the value does change however the display value does not and I can't figure out what is going wrong.
I am stuck please, if you can point me in the right direction or tell me what I am doing wrong that would be greatly appreciated.
Basically I am going to have multiple DatePickers in this popup and will submit them to a DB or a web service when I am done when they hit submit.
I can post the rest of the code if needed.
First suggestion is that try using React-Native-Community-Date-Picker
and seems like there are some mismatch between your DatePicker props and your state attributes.
for example if you want to change signInDate in your state then your setState should look something like this this.setState({ signInDate: value }); and onDateChange would look like onDateChange={this.onDateChange}

Set value of Reactstrap's Input to empty string

How do I set the value of a Reactstrap Input to be empty? I am using code like this.
handleChange = (event) => {
this.setState({message: event.target.value});
};
< Input onChange = {this.handleChange}/>
Also, what is the best practice for getting the value of an input: refs or onChange?
You gotta set a value property for your input which holds the value of your input, so your input looks like this:
<Input value={this.state.message} onChange={this.handleChange} />
and then when you want to clear its value, you just do this:
this.setState({message: ''})
and for your other question, the answer is that the Refs provide a way to access DOM nodes or React elements created in the render method, according to React documentation You can use Refs when:
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
and you have to AVOID using refs for anything that can be done declaratively.
Then, here we just use onChange because we don't simply need Refs!
You need to assign state value to your input field.
public class myApp() extends React.Component {
constructor(props){
super(props);
this.state = {
message: ''
};
}
handleChange = (event) => {
this.setState({message: event.target.value});
};
render() {
return (
<Input value={this.state.message} onChange={this.handleChange} />
);
}
}

React: update state with props change - handleChange and getDerivedStateFromProps

I'm trying to make some component which data output depends on some external API.
So I have this snippet:
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
somethingFromAPI: ''
}
}
componentDidMount() {
/*
something on axios.get() which updates this.state.somethingFromAPI
which normally can have some time delay till executed
*/
}
render() {
return (
<Child value={this.state.somethingFromAPI} />
)
}
}
class Child extends Component {
constructor(props) {
super(props)
this.state = {
value: this.props.value || ''
}
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
static getDerivedStateFromProps(props, state) {
// if difference
return {
value: props.value
}
}
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleChange.bind(this)} />
</div>
)
}
}
ReactDOM.render(
<Parent />
document.getElementById('app')
);
Seems like this works fine, initializing component, and getting API data, after that, input value seems to be updated, which is what I expect.
Problem that hurts me a lot is if I type something inside input, that will call handleChange, but will also trigger this getDerivedStateFromProps and will replace newer inputed value with that "old" from API.
Is this good way of doing this, maybe I made mistake at start with understanding of how it should be done? Guide me in right direction.
I'm yet pretty new to React.
Generally, need to make form which I can use for new input, or updating existing data (like some posts, etc.), so I can load API data.
Best regards.
Did you consider using shouldComponentUpdate instead if using getDerivedStateFromProps
something like this may solve your problem:
shouldComponentUpdate(nextProps, nextState) {
const { value: nextPropsValue } = nextProps;
const { value: propsValue } = this.props;
const { value } = this.state;
if (nextPropsValue !== propsValue && nextPropsValue !== value) {
this.setState({
value: nextPropsValue
});
}
return value !== nextState.value;
}
Update the answer adding comparison with current props value
I think using getDerivedStateFromProps here may be unnecessary. If you want to prevent a render in certain cases, consider using shouldComponentUpdate https://reactjs.org/docs/react-component.html#shouldcomponentupdate. But it sounds like you basically just need to use your input change handler to keep the state of the input, which you're already doing.
You should also check this article out on why someone shouldn't use getDerivedStateFromProps. It's very informative.

React - input date field not updating value in state

I am creating a date picker field in my React App.
import React, { Component } from 'react'
...
DateInput.propTypes = {
type: oneOf(['date']),
placeholder: string.isRequired,
maxLength: string,
disabled: bool,
}
export default DateInput
I tried this.change like other fields but that does not work either.
How to get the new value updated in the state ?
If you want the DateInput to reflect the state of it's parent component (this.state.age), then you have to somehow make the DateInput display this age.
This is done by the use of props.
Since DateInput is a wrapper around a plain input element you should use the value and onChange (not change) props:
render() {
let {
...
...
age,
...
} = this.state
...
...
//date of birth
let stringAge = age.toString()
stringAge = stringAge.substring(0, 4) + '-' +
stringAge.substring(4, 6) + '-' +
stringAge.substring(6, 8)
...
<DateInput
type="date"
value={age}
onChange={this.changeDOB}
placeholder={stringAge}
className="datePicker"
/>
}
This is what one could call a "controlled" input. Whenever possible, a React component should be made "pure" that is a pure function of its props.
Also the changeDOB handler should be bounded to the component instance otherwise this won't be what you expect and the this.setState(...) call will fail.
This can be done either in the contructor (boring but better*):
contructor(props) {
super(props);
this.changeDOB = changeDOB.bind(this);
}
or when defining the method (convenient but with caveats**):
changeDOB = () => {
this.setState({ age: document.getElementByClassNames("datePicker").value })
}
or when attaching the handler to the prop (discouraged***):
<DateInput
type="date"
value={age}
onChange={() => this.changeDOB()}
placeholder={stringAge}
className="datePicker"
/>
Here the DateInput is a controlled component (as in controlled by its props and therefore by its parent), both in display (age) and behavior (onChange).
The parent component becomes the child component's controller. This way of thinking is everywhere in React.
(* it's the most standard and performant way of doing it)
(** some IDE are not fond of this when it comes to intellisense)
(*** it's a performance issue because it generates new instances for a value of a prop during each render)

Redux form - cursor jumping to the end of the input field

I have a following class
export default class TestInput extends Component {
state = {
modified: false
};
change = e => {
this.setState({ modified: true });
this.props.input.onChange(e.target.value);
};
render() {
return (
<input type="text" value={this.props.input.value} onChange={this.change} className={!this.state.modified && this.props.meta.pristine ? 'default' : 'modified'} />
);
}
}
that I'm using like this
<Field component={TestInput} name="testProp" />
Whenever I place a cursor in the middle of the text in the field and write a letter, the letter appears at the right place but the cursor jumps to the end of the field. This is caused by the line this.setState({ modified: true }); and subsequent class change. If I comment out this line, this is not happening. I don't understand it. What am I doing wrong? Can I do something about it?
I am encountering this issue right now.
Here is how I am solving it.
Most modern browsers including ie11 support a property on input dom nodes called selectionStart, this property indicates where cursor position is, (note it is not 0 indexed, but begins at 1). The sibling setter property is setSelectionRange(begin, end). If you can capture the actual node's cursor position when its change event is fired, you can set the node's cursor position after the component has rendered, and the input thinks it has received new text input moving its cursor to the end of the new input.
Disclaimer: YOU WILL HAVE TO USE REACT REFS
Depending on your stack, the code might look like this.
class MyForm extends React.Component {
constructor(props) {
super(props)
this.state = { selectionStart }
this.inputElRef = React.createRef();
this.preserveCursor = this.preserveCursor.bind(this)
this.setCursor = this.setCursor.bind(this)
this.handleOnChange = this.handleOnChange.bind(this)
}
preserveCursor() {
this.setState({ selectionStart: this.inputElRef.current.selectionStart })
}
setCursor() {
this.inputElRef.current.setSelectionRange(
this.state.selectionStart,
this.state.selectionStart,
)
}
handleOnChange() {
this.preserveCursor()
}
componentDidUpdate() {
this.setCursor()
}
render() {
const { ...props } = this.props;
<div>
<form>
<input ref={this.inputElRef} { ...props } onChange={this.handleOnChange} name="foo" />
</form>
}
}
export default connect()(reduxForm({ name: 'MyForm' })(MyForm)
Note: If you use something like react-toolbox instead of a raw dom input
you will need to pass innerRef instead of ref, and that value should be a bound function of the form (el) => { this.myProperty = el }, which will give you access to the ref even though react-toolbox does not have awareness of ref, the extend react component has awareness of innerRef...
If you are using a value from the redux store in the textfield and updating the value of the redux store onChange. The problem is observed from react-redux version 6.0.1 and higher. Change your react-redux version to 6.0.0 and the cursor jumping problem should be solved.
This happens on the onChange event, i.e, every time you try to change the value of the input your change() function gets fired, in which you have a this.setState({ modified: true }) as you might know that this.setState forces the component to rerender, and know this time since !this.state.modified will return false, so the class gets changed to modified, which means it is working just fine, the cursor jumping to the end might have something to do your modified class, other than that nothing's wrong.
You might need to look and rephrase your question, what is it that you want should happen?
Just change value to defaultValue. It will work perfectly. 👍

Resources