Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

onChange not invoked when textarea resizes if state is updated in onResize callback #109

Open
vlazh opened this issue Oct 14, 2018 · 7 comments
Labels

Comments

@vlazh
Copy link

vlazh commented Oct 14, 2018

On controlled component onChange not invoked on autoresizing.

<TextareaAutosize
  value={text}
  onChange={this.changeText} // not invoked on autoresizing
  onResize={this.updateSelfHeight} // just updating parent height
/>
@FrancescoCioria
Copy link
Contributor

Hi @vlazh ,

onChange is called only when the user inputs a new value, why would you want it to be called when the textarea resizes? it would be called with the same value you should already have in you state.

The callback called when on autoresizing is onResize

@vlazh
Copy link
Author

vlazh commented Oct 15, 2018

Just try type 'enter' or some letter when textarea is full and then textarea resized ( onResize invoked) but 'new line' or typed letter will not be present in controlled value, because onChange not invoked.

@FrancescoCioria
Copy link
Contributor

FrancescoCioria commented Oct 15, 2018

I'm sorry but I cannot reproduce it:

Image from Gyazo

You can test it yourself here: https://react-components.buildo.io/#textareaautosize

What are you doing in the updateSelfHeight and changeText callback? The bug might be there

@FrancescoCioria
Copy link
Contributor

Sorry I missed the "when textarea is full" part, anyway, I tested it and I cannot reproduce it nevertheless:

Image from Gyazo

NOTE: the textarea is "controlled" through state.value so you would not see b if onChange hadn't been called correctly

@vlazh
Copy link
Author

vlazh commented Oct 15, 2018

Try this code:

initialState = { value: '', height: 30 };

<TextareaAutosize
  value={state.value}
  onChange={e => { setState({value:e.target.value}); }}
  onResize={e => { setState({height:e.target.clientHeight}); }}
  placeholder='try writing some lines'
/>

@FrancescoCioria
Copy link
Contributor

Thanks for the code, I finally managed to reproduce it :)

The reason your code isn't working is quite complicated:

  1. your textarea is "controlled": it will always show exactly this.props.value
  2. when you type a character that triggers a resize, onResize is fired before onChange
  3. you're calling setState in your callback, which forces a re-render

Put those three together and:
your onResize callback is called before onChange and, as you're triggering a re-render with setState, textarea is updated with the same value as before => React invalidates the onChange event as it thinks you just programmatically changed the value.
NOTE: if the textarea is not "controlled" onChange is called correctly as React does not invalidate the onChange event

To make your code work you could defer the setState in onResize:

initialState = {
  value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  height: 30
};

<TextareaAutosize
  value={state.value}
  onChange={e => {
    setState({ value: e.target.value });
  }}
  onResize={e => {
    const height = e.target.clientHeight
    setTimeout(() => setState({ height }))
  }}
/>;

(I have to analyse the issue further to understand if it's a good idea to defer that event directly in textarea's code)

@vlazh
Copy link
Author

vlazh commented Oct 16, 2018

Ok, thanx!
At now I just manually invoke setState in onResize with event.target.value to update textarea value.

@FrancescoCioria FrancescoCioria changed the title onChange not invoked on resizing onChange not invoked when textarea resizes if state is updated in onResize callback Oct 16, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants