2

I'm building an app in react and one facet of it involves recording the activity from a textarea and displaying it in real time at a different place in the app. I have the textarea bound to an onChange event and the onChange is firing, but the problem I'm having is that the onChange function keeps recording the inputs one keystroke too late. For example, if I typed "hello" in the textarea, the onChange listener would record and output "hell".

Code is below. thanks for your help!

The component code:

export default class StepTwo extends React.Component {

constructor(props) {

        super(props);

        this.state={
            headlineText: '',
        }

        this.writeHeadlineChild = this.writeHeadlineChild.bind(this);


    }

    updateHeadlineValue(evt) {

        this.setState({
                    headlineText: evt.target.value
                })

    }

    writeHeadlineChild(e) {

        e.preventDefault();
        e.stopPropagation();
        e.nativeEvent.stopImmediatePropagation();

        this.props.headWriter(this.state.headlineText, this.state.headlineFont);


    }

        render() {

            return (

        <
        form className = "card-form"
        onChange = {
            (e) => {
                this.writeHeadlineChild(e)
            }
        } >

        <
        div className = "form-group"
        onChange = {
            evt => this.updateHeadlineValue(evt)
        } >
        <
        label htmlFor = "headline"
        className = "form-label" > Your message < /label> <
        textarea className = "form-control"
        id = "headline" > < /textarea> <
        /div> <
        /form>

        <
        /div>
        )
    }

}

And the function in the parent component:

writeHeadline(t, f) {

    var headline = document.querySelector('.headline');

    function headlinePreview() {
        headline.innerHTML = t;
        headline.style.fontFamily = f;
    }

    headlinePreview();

}
toofarm
  • 45
  • 1
  • 6
  • What happens if you replace onchange with onkeyup? – Matt Fletcher Dec 25 '17 at 19:24
  • Use the onkeyup or onkeydown depending on the time you want to capture the change. – jackotonye Dec 25 '17 at 19:33
  • Thanks for the help, everyone. It turned out the problem was resulting from the way I was handing state. The info from the text field was being held as a "pending state value" and wasn't passing at the proper time. There's a good explanation of it [in this post](https://stackoverflow.com/questions/28773839/react-form-onchange-setstate-one-step-behind#28774088) – toofarm Dec 27 '17 at 18:38

2 Answers2

1

I see something interesting here - you are calling onChange on the div and the form, rather than the element that is actually responsible for propogating the change. In this case the textarea node is responsible for changes, so we can handle state updates as result to changes on that element only.

Update your component so that the textarea handles its own events (removing them from form and div)

So something like <textarea onChange={this.handleChange}/>

followed by

handleChange(evt) {
  const { value } = evt.target 
  // followed by any state changes, or props callbacks
  this.setState({ headlineText: value })
}

should be sufficient enough to manage the value of your textarea field.

random-forest-cat
  • 33,652
  • 11
  • 120
  • 99
0

It looks like your headline isn't directly tied to the react state change. Your form has its' own onchange() function which is going to fire any time the form itself changes, but it's reading data that's not controlled by react, so there's no guarantees that the data's going to be an accurate reflection of the state as set by the input.

Knowing that any time a state is set the render() method of the Component is called, you can capitalize on this by calling your writeHeadline() method from your parent component after the render() method is called, but before the return() statement. It should ideally use this.state.headlineText as the text parameter.