Реагировать отображение строк строки из сохраненного текстового поля

Использование Facebook React. На странице настроек у меня есть многострочный textarea, где пользователь может вводить многострочный текст (в моем случае - адрес).

<textarea value={address} />

Когда я пытаюсь отобразить адрес, что-то вроде {address}, он не показывает разрывы строк и все в одной строке.

<p>{address}</p>

Есть идеи, как это решить?

Ответы

Ответ 1

Нет смысла использовать JS. Вы можете легко сказать браузеру, как обращаться с новой строкой, используя свойство white-space CSS:

white-space: pre-line;

pre-line

Последовательности пробелов сбрасываются. Строки разбиты на символы новой строки, в <br> и, если необходимо, для заполнения строк.

Посмотрите эту демонстрацию:

<style>
  #p_wrap {
    white-space: pre-line;
  }
</style>

<textarea id="textarea"></textarea>
<p id="p_standard"></p>
<hr>
<p id="p_wrap"></p>
<script>
  textarea.addEventListener('keypress', function(e) {
    p_standard.textContent = e.target.value
    p_wrap.textContent = e.target.value
  })
</script>

Ответ 2

Этого и следовало ожидать, вам нужно преобразовать символы новой строки (\n) в разрывы строк HTML

Статья об использовании его в реакции: Реагировать на новую строку, чтобы прервать (nl2br)

Цитировать статью:

Поскольку вы знаете, что все в React - это функции, вы не можете этого делать

this.state.text.replace(/(?:\r\n|\r|\n)/g, '<br />')

Так как это вернет строку с узлами DOM внутри, это тоже недопустимо, потому что это должна быть только строка.

Затем вы можете попробовать сделать что-то вроде этого:

{this.props.section.text.split('\n').map(function(item) {
  return (
    {item}
    <br/>
  )
})}    

Это также недопустимо, потому что React снова является чистыми функциями, и две функции могут быть рядом друг с другом.

tldr. Решение

{this.props.section.text.split('\n').map(function(item) {
  return (
    <span>
      {item}
      <br/>
    </span>
  )
})}

Теперь мы переносим каждый разрыв строки в промежутке, и это прекрасно работает, потому что промежутки имеют встроенное отображение. Теперь мы получили работающее решение для разрыва строки nl2br

Ответ 3

Решение состоит в том, чтобы установить свойство white-space в элементе, отображающем содержимое вашего textarea:

white-space: pre-line;

Ответ 4

Начиная с React 16, компонент может возвращать массив элементов, что означает, что вы можете создать такой компонент:

export default function NewLineToBr({children = ""}){
  return children.split('\n').reduce(function (arr,line) {
    return arr.concat(
      line,
      <br />
    );
  },[]);
}

который вы бы использовали следующим образом:

<p>
  <NewLineToBr>{address}</NewLineToBr>
</p>

Ответ 5

Предыдущее предложение Пита с автономным компонентом - отличное решение, хотя оно упускает одну важную вещь. Спискам нужны ключи. Я немного изменил его, и моя версия (без предупреждений консоли) выглядит следующим образом:

const NewLineToBr = ({ children = '' }) => children.split('\n')
  .reduce((arr, line, index) => arr.concat(
    <Fragment key={index}>
      {line}
      <br />
    </Fragment>,
  ), [])

Он использует React 16 Фрагменты

Ответ 6

Люблю вебит версию. Я не знал о компоненте Fragment, он настолько полезен. Нет необходимости использовать метод сокращения, хотя. Карта достаточно. Кроме того, для списка действительно нужны ключи для реагирования, но для него плохо использовать индекс из метода итерации. Эслинт продолжал разбивать это в моем предупреждении, пока у меня не было ошибки путаницы. Так бы это выглядело так:

const NewLine = ({ children }) =>
   children.split("\n").map(line => (
    <Fragment key={uuidv4()}>
      {line}
      <br />
    </Fragment>
  ));