Вернемся от теории к практике: давайте покликаем по ссылкам-кнопочкам, поизменяем свойства компонентов...
Упс, не выйдет! Как вы помните, свойства (this.props) следует использовать только для чтения, а для динамических свойств нужно использовать так называемое "состояние" (state).
Итак, встречайте - this.state ;)
Так как мне нужно в этом разделе сохранить минимум теории и больше практики, сразу перейдем к делу. Предлагаю вместе решить следующую задачу: у новости есть ссылка "подробнее", по клику на которую - бинго, текст новости целиком.
Начнем с изменения данных:
const myNews = [ { id: 1, author: 'Саша Печкин', text: 'В четверг, четвертого числа...', bigText: 'в четыре с четвертью часа четыре чёрненьких чумазеньких чертёнка чертили чёрными чернилами чертёж.' }, { id: 2, author: 'Просто Вася', text: 'Считаю, что $ должен стоить 35 рублей!', bigText: 'А евро 42!' }, { id: 3, author: 'Max Frontend', text: 'Прошло 2 года с прошлых учебников, а $ так и не стоит 35', bigText: 'А евро опять выше 70.' }, { id: 4, author: 'Гость', text: 'Бесплатно. Без смс, про реакт, заходи - https://maxpfrontend.ru', bigText: 'Еще есть группа VK, telegram и канал на youtube! Вся инфа на сайте, не реклама!' } ];
Затем, научимся отображать полный текст новости сразу после вводного текста:
class Article extends React.Component { render() { const { author, text, bigText } = this.props.data // вытащили bigText из даты return ( <div className='article'> <p className='news__author'>{author}:</p> <p className='news__text'>{text}</p> <p className='news__big-text'>{bigText}</p> </div> ) } } Article.propTypes = { data: PropTypes.shape({ author: PropTypes.string.isRequired, text: PropTypes.string.isRequired, bigText: PropTypes.string.isRequired // добавили propTypes для bigText }) }
Опять же, больше ничего изменять не нужно. Данные корректно отобразятся.
Проверим...
Отлично, можно продолжать работу: добавим ссылку - "подробнее". Приведу фрагмент кода:
... return ( <div className='article'> <p className='news__author'>{author}:</p> <p className='news__text'>{text}</p> <a href="#" className='news__readmore'>Подробнее</a> <p className='news__big-text'>{bigText}</p> </div> ) ...
Проверьте и если все ок - мы готовы к работе с состоянием компонента.
С состоянием (state) можно работать только в statefull компонентах (class)
Если вы определяете какое-то изменяемое свойство в компоненте, необходимо указать начальное состояние (в терминологии react.js - initial state). Для этого, у компонента нужно просто определить свойство state:
class Article extends React.Component { state = { visible: false, // определили начальное состояние } render() { const { author, text, bigText } = this.props.data return ( <div className='article'> <p className='news__author'>{author}:</p> <p className='news__text'>{text}</p> <a href="#" className='news__readmore'>Подробнее</a> <p className='news__big-text'>{bigText}</p> </div> ) } }
Посмотрим в консоли на вкладке React:
В состоянии (в state) появилось свойство. Будем использовать его в момент render'а.
Формализуем задачу:
Будем использовать логическое выражение внутри JSX, значит - фигурные скобки, и внутри js-выражение.
class Article extends React.Component { state = { visible: false, } render() { const { author, text, bigText } = this.props.data const { visible } = this.state // вытащили visible из this.state return ( <div className='article'> <p className='news__author'>{author}:</p> <p className='news__text'>{text}</p> { /* если не visible, то показывай */ !visible && <a href="#" className='news__readmore'>Подробнее</a> } { /* если visible, то показывай */ visible && <p className='news__big-text'>{bigText}</p> } </div> ) } }
Мы использовали одну и ту же переменную состояния в двух местах когда описывали обычное javascript выражение. Если вы не знакомы с И / ИЛИ, то рекомендую почитать у Кантора ().
Обратите внимание, для написания комментариев не понадобились дополнительные фигурные скобки, так как мы уже находились внутри "выражения" внутри JSX.
Можете проверить в браузере, и покликать на чекбокс внутри state зоны. Шаблон уже будет реагировать. А мы продолжим делать все это по-человечески, чтобы можно было кликать на "подробнее".
Чтобы обработать клик, нам необходимо указать атрибут onClick у элемента.
В качестве обработчика у нас будет функция, которая изменяет состояние. Для изменения состояния, нужно обязательно использовать метод setState, а не перезаписывать значение переменной в this.state напрямую.
class Article extends React.Component { state = { visible: false, } handleReadMoreClck = (e) => { // добавили метод e.preventDefault() this.setState({ visible: true }) } render() { const { author, text, bigText } = this.props.data const { visible } = this.state return ( <div className='article'> <p className='news__author'>{author}:</p> <p className='news__text'>{text}</p> { /* добавили onClick */ !visible && <a onClick={this.handleReadMoreClck} href="#" className='news__readmore'>Подробнее</a> } { visible && <p className='news__big-text'>{bigText}</p> } </div> ) } }
Проверьте в браузере, кликните на ссылку "подробнее".
Каждый компонент <Article />
имеет свое состояние! Поэтому, при клике на подробнее в одном из компонентов, только его состояние изменяется, и только у этой новости отображается полный текст.
Итого:
Для сохранения динамических свойств, используется состояние (state) компонента.
Для обработки клика, используется свойство onClick + функция-обработчик. Существуют и другие стандартные события, которые работают по такому же принципу. Полный список . Мы будем знакомиться с ними по мере необходимости.
Для изменения состояния, используется метод setState, который принимает объект с аргументами, которые нужно изменить. Например, у нас есть состояние:
... state = { visible: false, rating: 0, eshe_odno_svoistvo: 'qweqwe' } ...
Чтобы изменить рейтинг, нужно написать следующий setState:
this.setState({rating: 100500})
Чтобы изменить все три свойства:
this.setState({ rating: 100500, visible: true, eshe_odno_svoistvo: 'привет' })
Так же у setState есть возможность указать callback функцию, которая будет вызвана после того, как новое состояние "установится".
... readmoreClick: function(e) { e.preventDefault(); this.setState({ visible: true }, () => { alert('Состояние изменилось'); }); }, ...
Еще setState есть возможность... (на самом деле есть, но с нас пока хватит).
Посмотреть полный список возможностей setState можно в .
на данный момент.