title: React js textarea onchange doesn't work with value
body: <p>Here is my class component which is a twitter like auto-suggest text area.</p>
  <pre><code>import React, { Component, createRef } from 'react';
      import { TextArea, List, Triangle } from './Styled';
      import getCaretCoordinates from 'textarea-caret';
      
      class AutoCompleteTextArea extends Component {
          constructor(props) {
              super(props);
              this.state = {
                  value: &quot;&quot;,
                  caret: {
                      top: 0,
                      left: 0,
                  },
                  isOpen: false,
                  matchType: null,
                  match: null,
                  list: [],
                  selectionEnd: null,
              };
              this.users = [
                  { name: 'Bob', id: 'bobrm' },
                  { name: 'Andrew', id: 'andrew_s' },
                  { name: 'Simon', id: 'simon__a' },
              ];
              this.hashtagPattern = new RegExp(`([#])(?:(?!\\1)[^\\s])*$`);
              this.userPattern = new RegExp(`([@])(?:(?!\\1)[^\\s])*$`);
              this.textareaRef = createRef();
          }
      
          componentDidMount() {
              var caret;
              document.querySelector('textarea').addEventListener('input', (e) =&gt; {
                  caret = getCaretCoordinates(e.target, e.target.selectionEnd);
                  this.setState({ caret });
              });
          }
      
          keyDown = (e) =&gt; {
              this.autosize();
              const code = e.keyCode || e.which;
              // Down
              //if (code === 40) down()
              // Up
              //if (code === 38) up()
              // Enter
              //if (code === 13) onSelect()
          };
      
          onChange = (e) =&gt; {
              const { selectionEnd, value } = e.target;
              console.log(value);
              this.setState({ value });
              const userMatch = this.userPattern.exec(value.slice(0, selectionEnd));
              const hashtagMatch = this.hashtagPattern.exec(
                  value.slice(0, selectionEnd)
              );
              if (hashtagMatch &amp;&amp; hashtagMatch[0]) {
                  this.setState({
                      matchType: hashtagMatch[1],
                      match: hashtagMatch[0],
                      selectionEnd,
                  });
                  this.suggest(hashtagMatch[0], hashtagMatch[1]);
              } else if (userMatch &amp;&amp; userMatch[0]) {
                  this.setState({
                      matchType: userMatch[1],
                      match: userMatch[0],
                      selectionEnd,
                  });
                  this.suggest(userMatch[0], userMatch[1]);
              } else {
                  this.setState({
                      match: null,
                      matchType: null,
                      isOpen: false,
                  });
              }
          };
      
          suggest = (match, matchType) =&gt; {
              if (matchType === '#') {
                  someRequest.then((res) =&gt; {
                      this.setState({
                          list: res.body,
                          isOpen: res.body.length !== 0,
                      });
                  });
              } else if (matchType === '@') {
                  this.setState({
                      list: this.users,
                      isOpen: this.users.length !== 0,
                  });
              }
          };
      
          autosize = () =&gt; {
              var el = document.getElementsByClassName('autoComplete')[0];
              setTimeout(function() {
                  el.style.cssText = 'height:auto; padding:0';
                  el.style.cssText = 'height:' + el.scrollHeight + 'px';
              }, 0);
          };
      
          hashtagClickHandler = (hashtag) =&gt; {
              const { selectionEnd, match, matchType, value } = this.state;
              const select = matchType + hashtag;
      
              // It's replace value text
              const pre = value.substring(0, selectionEnd - match.length) + select;
              const next = value.substring(selectionEnd);
              const newValue = pre + next;
              console.log(newValue);
              this.setState({ isOpen: false, value: newValue });
              this.textareaRef.current.selectionEnd = pre.length;
          };
      
          render() {
              return (
                  &lt;&gt;
                      &lt;TextArea
                          id=&quot;postText&quot;
                          name=&quot;postText&quot;
                          placeholder=&quot;What's on your mind ? ...&quot;
                          maaxLength={255}
                          className=&quot;autoComplete&quot;
                          onKeyDown={this.keyDown}
                          onChange={this.onChange}
                          value={this.state.value}
                          ref={this.textareaRef}
                      /&gt;
                      {this.state.isOpen &amp;&amp; (
                          &lt;List top={this.state.caret.top}&gt;
                              &lt;Triangle left={this.state.caret.left} /&gt;
                              {this.state.matchType === '#'
                                  ? this.state.list.map((hashtag, index) =&gt; (
                                        &lt;button
                                            key={'hashtag' + index}
                                            className=&quot;listItem&quot;
                                            onClick={() =&gt;
                                                this.hashtagClickHandler(
                                                    hashtag,
                                                    index
                                                )
                                            }
                                        &gt;
                                            &lt;h5&gt;{`#${hashtag}`}&lt;/h5&gt;
                                        &lt;/button&gt;
                                    ))
                                  : this.state.list.map((user, index) =&gt; (
                                        &lt;button
                                            key={'user' + index}
                                            className=&quot;listItem&quot;
                                        &gt;
                                            &lt;h5&gt;{user.name}&lt;/h5&gt;
                                            &lt;p&gt;{user.id}&lt;/p&gt;
                                        &lt;/button&gt;
                                    ))}
                          &lt;/List&gt;
                      )}
                  &lt;/&gt;
              );
          }
      }
      
      export default AutoCompleteTextArea;
  </code></pre>
  <p>When I have both value and onChange props on my TextArea it doesn't fire the onChange function. But if I remove the value prop it will be fired.
  Actually I need the onChange because I'm going to change the value when the user clicks on one of the hashtags suggested.
  My TextArea is just a styled component like this:</p>
  <pre><code>export const TextArea = styled.textarea`
      float: left;
      width: 450px;
      font-size: 16px;
      font-weight: lighter;
      margin: 22px 0 0 20px;
      border: none;
      &amp;::placeholder {
          color: ${(props) =&gt; props.theme.textGrayLight};
      }
      font-family: ${(props) =&gt; props.theme.mainFont};
      position: relative;
      resize: none;
  
      @media ${(props) =&gt; props.mediaHD} {
          width: 250px;
      }
  `;
  </code></pre>