React에서 행 수 가변 textarea를 만든 이야기

TL;DR





내용에 따라 높이가 바뀌는 textarea가 생겼다.
Copipe, 여러 줄을 함께 삭제해도 괜찮습니다.

가볍게 검색해도 나오지 않았기 때문에
비슷한 것을 하고 싶은 사람이나 미래의 자신을 위해서 써 보았습니다

환경



react:15.6.2
redux-form:6.8.0
lodash.isempty:4.4.0

솔직히 react만으로도 괜찮을 것입니다.
폐지되는 라이프 사이클 메소드 등도 사용하고 있지 않기 때문에 최신판의 react에서도 움직인다고 생각합니다

다른 2 개는 세세한 곳 쓰는 것이 귀찮기 때문에 사용하고 있습니다
없어도 본질에는 관계 없기 때문에 괜찮습니다.

chrome과 IE에서 동작 확인 완료 (버전은 모르지만 2020/01 부근입니다)

참고



textarea의 크기를 자동 조정

구현



자세한 내용은 느낌으로 읽으십시오.

index.js
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import TextArea from './textArea';

function index() {
  return (
    <div>
      <Field name="TextArea" component={TextArea} rows={2} />
    </div>
  )
}

export default reduxForm({ form: 'form' })(index);

textArea.js
import React, { Component } from 'react';
import isEmpty from 'lodash.isempty';

class TextArea extends Component {
  constructor(props) {
    super(props);
    this.textArea = null;
  }

  shouldComponentUpdate(nextProps) {
    if (this.props.input.value !== nextProps.input.value) {
      if (isEmpty(nextProps.input.value)) {
        this.textArea.setAttribute('rows', this.props.rows);
      } else {
        this.textArea.setAttribute('rows', this.props.rows);
        while (this.textArea.scrollHeight > this.textArea.offsetHeight) {
          const tempRows = Number(this.textArea.getAttribute('rows'));
          this.textArea.setAttribute('rows', tempRows + 1);
        }
      }
    }
    return true;
  }

  render() {
    return (
      <textarea
        ref={c => {
          this.textArea = c;
        }}
        style={{ resize: 'none' }}
        name={this.props.input.name}
        onChange={e => this.props.input.onChange(e.target.value, this.props.input.name)}
        rows={this.props.rows}
      />
    );
  }
}

해설



참고로 한 코드와 비슷한 것을하고 있습니다.
다음 부분은 모두
  shouldComponentUpdate(nextProps) {
    // textareaの内容が変更された時のみ操作
    if (this.props.input.value !== nextProps.input.value) {
      if (isEmpty(nextProps.input.value)) {
        // 内容が空なら初期値の行数に戻すだけ
        this.textArea.setAttribute('rows', this.props.rows);
      } else {
        this.textArea.setAttribute('rows', this.props.rows);
        // 内容が有るならスクロールせずに表示できる高さになるまで初期値から1行ずつ増やす
        while (this.textArea.scrollHeight > this.textArea.offsetHeight) {
          const tempRows = Number(this.textArea.getAttribute('rows'));
          this.textArea.setAttribute('rows', tempRows + 1);
        }
      }
    }
    return true;
  }

주의점



높이에 max-height 등으로 상한을 정하고 싶을 때는
직접 textarea에 max-height를 쓰지 마십시오.

높이 계산과 충돌하거나 무한 루프가되어 브라우저가 굳어집니다.
높이를 결정하고 싶은 경우는 적당히 랩 해 그쪽에 여러 가지 설정해 주세요

※이번에 말하면, index.js의 div에 {max-height: 100px, overflow-y: scroll}같이 하면
100px보다 입력란이 높아지면 스크롤이 되도록 전환됩니다

요약



shouldComponentUpdate에서 이런 일을하는 것이 좋을지 모르겠지만 우선 움직이고 있으므로 요시로합니다.
가로(cols)에도 같은 방법으로 확축할 수 있을까 생각합니다만 거기까지는 시도하지 않습니다

좋은 웹페이지 즐겨찾기