Loading...

how to set a textarea's selection in react using state instead of a ref?


i'm setting a textarea's selectionRange using a react ref, but that contradicts with the react "way" .

the ref is working perfectly .

i want to set the textarea's selectionRange using state, not a ref ( like in this code snippet )

import React, { Component } from 'react';

export default class App extends Component {

  constructor() {
    super();

    this.state = {
      value:"some placeholder text",
    }

    this.textareaRef = React.createRef();
  }

  handleChange=({ target : { value : text } })=>{
   this.setState({value : text});
  };

  componentDidMount(){
    // setting the cursor position to the end of text on mount .
    const textareaObj = textareaRef.current;
    const cursor_pos = this.state.value.length;

    textareaObj.setSelectionRange(cursor_pos , cursor_pos );
    textareaObj.focus();
  }

  render(){
    return (
    <textarea 
      value={this.state.value} 
      onChange={this.handleChange}
      ref={textareaRef}>
    </textarea>
    );
  }
}
- - Source

Answers

answered 1 week ago tombraider #1

You're looking to create a "controlled" component, as in React should control the state of the element rather than the DOM.

You're half way there, just a couple of tweaks: https://jsfiddle.net/tombarton/2s5q398c/3/

class TextArea extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
        inputValue: 'Here is some content...'
    }
    this.onTextareaChange = this.onTextareaChange.bind(this);
  }

  onTextareaChange(e) {
    const { value } = e.target;
    this.setState(state => ({
        ...state,
      inputValue: value,
    }))
  }

  render() {
    return (
      <div>
        <textarea value={this.state.inputValue} onChange={this.onTextareaChange} />
      </div>
    )
  }
}

ReactDOM.render(<TextArea />, document.querySelector("#app"))

As you can see, we assign a value from the component's state to the value attribute of the textarea element. To complete the process, we assign a method to update the state to the onChange attribute of the element. When the onChange event fires, it is passed into our method, we extract the updated value and update our component's state. As we're passing our method outside of the class, we have to bind this to it, as you can see in the constructor.

Hope that helps.

answered 1 week ago Alexey Baguk #2

I see it like this:

export default class App extends Component {

  constructor() {
    super();

    this.state = {
      value:"some placeholder text",
    }
  }

  handleChange=({ target : { value : text } })=>{
    this.setState({value : text});
  };

  render(){
     return (
       <textarea 
         value={this.state.value} 
         onChange={this.handleChange}
         ref={this.setCursorPos}>
       </textarea>
    );
  }

  setCursorPos = (textarea) => {
    const cursor_pos = this.state.value.length;

    textarea.setSelectionRange(cursor_pos , cursor_pos );
    textarea.focus();
  }
}

answered 1 week ago dporechny #3

What you want to do is to set selectionStart and selectionEnd textarea properties using state without using refs? Something like this:

render(){
  const { value } = this.state;
  const startingPoint = 0;
  return (
    <textarea 
      value={this.state.value} 
      selectionStart={startingPoint}
      selectionEnd={startingPoint + value.length}
    </textarea>
  );
}

But currently it's not possible, you can take a look at all <textarea>'s properties here. So using refs in this case is perfectly fine.

comments powered by Disqus