Created
January 5, 2019 16:24
-
-
Save mjsarfatti/6e1261f0be5f3c9eef5da1cda7bd3ffe to your computer and use it in GitHub Desktop.
Async setState in React (and especially often when used w/ state management libs like 'unstated') can cause the caret in a form to jump
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
export default function withSyncChange(WrappedComponent) { | |
return class extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
value: props.value, // initial value | |
parentValue: props.value, // tracking the parent value | |
}; | |
this.handleChange = this.handleChange.bind(this); | |
} | |
// This is all basically to mimic componentWillReceiveProps. | |
// Do you have a better solution? | |
static getDerivedStateFromProps(props, state) { | |
// Any time the value from the parent Component changes: | |
if (props.value !== state.parentValue) { | |
if (props.value !== state.value) { | |
// Update both the tracker and the input value if needed, | |
// this will affect the <input> field, but not reset the caret | |
// since handleChange will have already updated the value. | |
return { | |
parentValue: props.value, | |
value: props.value, | |
}; | |
} else { | |
// Otherwise update our tracker to remain in sync, | |
// this will not reset the caret either. | |
return { | |
parentValue: props.value, | |
}; | |
} | |
} | |
return null; | |
} | |
handleChange(e, data) { | |
this.setState({ value: e.target.value }); | |
if (this.props.onChange) { | |
e.persist(); | |
// According to https://stackoverflow.com/a/43232616/416714 we need to | |
// debounce this to avoid race conditions when typing really fast. I | |
// tested random-typing really really fast and it never failed me though. | |
this.props.onChange(e, data); | |
} | |
} | |
render() { | |
return ( | |
<WrappedComponent | |
{...this.props} | |
value={this.state.value} | |
onChange={this.handleChange} | |
/> | |
); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage: