Основи ReactJS

10 хв. читання

React - бібліотека (не фреймворк) для UI.

Різні способи створення та керування компонентами в React, поява купи інструментів для управління станом та багато іншого часто заплутують новачків і викликають проблеми.

Тут ми розкажемо детально про деякі корисні речі, що можуть викликати труднощі в новачків. А саме це:

  • Володіння компонентами (Component Ownership)

  • Валідація властивостей

  • Взаємодія компонентів

  • Значення за умовчуванням

  • ES6+ компоненти (та їх відмінності від звичайних)

  • Незмінювані компоненти (Stateless Components)

Це базовий туторіал, тому не дивуйтесь, якщо знайдете щось знайоме.

Звичайні компоненти

Під "звичайними" я розумію загальні компоненти, котрі ви могли бачити в інших статтях:

var Hello = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

ReactDOM.render(
  <hello name="World">,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div>
    
</div>

Зауважте, що звичайний не означає найкращий. Це ті компоненти, що пропонує офіційна документація React і вони є базовими.

Функцію React.createClass потрібно передти аргументом Object. Цей об'єкт описує реакт-компонент. Властивість render є обов'язковою й найважливішою. Це HTML, що вбудовується в JS, JSX.

Веб-додатки цікаві лише коли вони інтерактивні. Кожна UI-бібліотека надає інтерфейс для обміну даними, а саме в React це об'єкт props. Тобто коли ви бачите наступний JSX:

<h1>My name is {name}</h1>

Це означає, що ми кажемо реакту "коли компонент буде вставлено, властивість name потрібно підставити в текст, що знаходиться всередині." Але цю властивість слід заздалегідь передати ось так:

<hello name="World">

Метод render приймає об'єкт, що потрібно вставити та DOM, куди його потрібно вставити. Ось це й є базовим принципом React-компонентів.

Стани та властивості

Динамічні додатки потребують передачі інформації всередині їх системи. В React передача даних зазвичай здійснюється між компонентами за зовнішніми сервісами, що ці дані надають (HTTP, localStorage).

Властивості є незмінними, що означає що вони можуть бути переданими тільки з батьківського компоненту. Це створює проблеми, адже сучасний додаток не може мати всі свої стани при завантаженні. Після виконання AJAX чи чи якихось інших подій, коли повертаються дані - їх потрібно обробити і оновити інтерфейс. От тут на допомогу приходять стани (states) компонентів.

При ініціалізації React ми оголошуємо початковий стан, що синхронізується з властивостями. А коли стан оновлюється - властивості можуть бути легко синхронізовані.

var Counter = React.createClass({
	getInitialState: function() {
    return {
    	counter: 0
    };
  },
  render: function() {
    return <div>
    		<h2>{this.props.name}</h2>
    		{this.state.counter}
      </div>;
  }
});

ReactDOM.render(
  <counter name="{'Counter'}">,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div>
    
</div>

Цей приклад може бути не дуже зрозумілим, але пізніше ми покажемо всю міць React-станів.

Володіння компонентом (батьківство)

Це досить просто. Якщо компонент в своєму методі render рендерить інший компонент, то він стає власником компоненту, який він відрендерив і може його контролювати.

Давайте розглянемо наступний приклад

var CounterDisplay = React.createClass({
	render: function(){
  	return <div>{this.props.counterProp}</div>
  }
})

var Counter = React.createClass({
	getInitialState: function() {
    return {
    	counter: 0
    };
  },
  render: function() {
    return <div>
    		<h2>{this.props.name}</h2>
    		<counterdisplay counterprop="{this.state.counter}"></counterdisplay>
      </div>;
  }
});

ReactDOM.render(
  <counter name="{'Counter'}">,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div>
    
</div>

Тепер Counter рендерить інший компонент CounterDisplay. Він може контролювати властивості дочірнього компоненту. Ви можете бачити як він контролює властивості дочірнього компоненту за допомогою своїх станів.

Взаємодія компонентів

А якщо в нас є кнопка (або декілька) в дочірньому компоненті, що збільшує або зменшує число в батьківському компоненті. Як нам слід вчинити в цьому випадку?

Взаємодія компонентів в React є двох видів: передача даних від батьківського до дочірнього компонентів та навпаки. Вище ми бачили як батьківський компонент передає дані в дочірній за допомогою властивостей.

Щоб передати дані від дочірнього до батьківського компонентів в React ми використовуємо перехоплювачі, що передаються з батьківського компонента до дочірнього через властивості. Батьківський компонент знає, яка активність може статися в дочірньому компоненті і тому передає хендлер/перехоплювач, що реагуватиме на цю активність.

Основи ReactJS

var CounterDisplay = React.createClass({
    render: function(){
    // Calls the handler props once events are fired
    return <div>
            <div>{this.props.counterProp}</div>
        <button onclick="{this.props.incrementCounter}">+</button>
        <button onclick="{this.props.decrementCounter}">-</button>
        </div>
  }
})

var Counter = React.createClass({
    getInitialState: function() {
    return {
        counter: 0
    };
  },
  handleIncrement(){
    // Update counter state
    this.setState({counter : this.state.counter+1});
  },
  handleDecrement(){
      // Update counter state
    this.setState({counter : this.state.counter-1});
  },
  render: function() {
    // Pass down handlers to CounterDisplay component
    return <div>
            <h2>{this.props.name}</h2>
            <counterdisplay counterprop="{this.state.counter}" decrementcounter="{this.handleDecrement}" incrementcounter="{this.handleIncrement}"></counterdisplay>
      </div>;
  }
});

ReactDOM.render(
  <counter name="{'Counter'}">,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div>
    
</div>

Компонент Counterdisplay має подію кліку. Так як перехоплювачі події не знайдено в самому компоненті, React шукає їх в батьківських компонентах, в даному випадку Counter. Перехоплювач кліку оновлює стан методом this.setState() в результаті чого значення оновлюється.

Значення за умовчуванням

Не тільки для станів можна задати стандартні значення через метод getInitialState. Якщо потрібно, ви можете задати початкові значення і для властивостей. Зробити це можна за допомогою вказання методу getDefaultProps:

getDefaultProps: function() {
     return {
       name: 'Counter'
     };
},

Валідація властивостей

Валідація дозволяє вам бути впевненим, що ваші компоненти будуть працювати як потрібно, а дані, що в них передаються будуть правильного типу.

var CounterDisplay = React.createClass({
    render: function(){
    return <div>
            <div>{this.props.counterProp}</div>
        <br>
        <button onclick="{this.props.incrementCounter}">+</button>
        <button onclick="{this.props.decrementCounter}">-</button>
        </div>
  },
  // Сама валідація
  propTypes: {
    // Число
    counterProp: React.PropTypes.number.isRequired,
    // Функції
    incrementCounter: React.PropTypes.func.isRequired,
    decrementCounter: React.PropTypes.func.isRequired
   }
})

Якщо вам потрібно лише перевіряти тип даних, коли вони передані, то вам слід прибрати isRequired:

propTypes: {
    counterProp: React.PropTypes.number,
    incrementCounter: React.PropTypes.func,
    decrementCounter: React.PropTypes.func
   }

Наприклад:

var CounterDisplay = React.createClass({
	render: function(){
  	// Calls the handler props once events are fired
  	return <div>
    		<div>{this.props.counterProp}</div>
        <br>
        <button onclick="{this.props.incrementCounter}">+</button>
        <button onclick="{this.props.decrementCounter}">-</button>
    	</div>
  },
  propTypes: {
    counterProp: React.PropTypes.number.isRequired,
    incrementCounter: React.PropTypes.func.isRequired,
    decrementCounter: React.PropTypes.func.isRequired
   }
})

var Counter = React.createClass({
	getInitialState: function() {
    return {
    	counter: 0
    };
  },
  handleIncrement(){
  	// Update counter state
  	this.setState({counter : this.state.counter+1});
  },
  handleDecrement(){
	  // Update counter state
  	this.setState({counter : this.state.counter-1});
  },
  render: function() {
  	// Pass down handlers to CounterDisplay component
    return <div>
    		<h2>{this.props.name}</h2>
    		<counterdisplay counterprop="{this.state.counter}" decrementcounter="{this.handleDecrement}" incrementcounter="{this.handleIncrement}"></counterdisplay>
      </div>;
  }
});

ReactDOM.render(
  <counter name="{'Counter'}">,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div>
    
</div>

Клас компоненту (ES6)

React.createClass - не єдиний спосіб створити компонент. З ES6 (він дуже крутий) ми можемо використовувати класи для створення своїх компонентів.

// Успадковуємо React.Component
class Comment extends React.Component {
 // Рендер тепер метод класу, а не властивість об'єкта
  render(){
    return <h1>{this.props.name}</h1>;
  }
}

 React.render(<comment name="{'Comment'}/">, document.getElementById('container'));

Тут ім'я класу це ім'я компонента, а наслідування React.Component переносить всю функціональність в наш клас.

Встановлення стану

Якщо ви вибрали написання компонентів за допомогою ООП, то деякі речі доведеться робити інакше. Наприклад, так оголошується початковий стан:

class Comment extends React.Component {
   constructor(props) {
        super(props);
        this.state = {
            counter: 0
        };
  }
  render(){
    return <h1>{this.props.name}</h1>;
  }
}

 React.render(<comment name="{'Comment'}/">, document.getElementById('container'));

Тут стан ініціалізується в конструкторі класу. Також важливо завжди передавати властивості до батьківського компоненту: super(props).

Властивості за умовчуванням та валідація

Як і встановлення початкового стану, стандартні властивості і валідація теж реалізується іншим чином:

// Валідація
Comment.propTypes = {
        counterProp: React.PropTypes.number.isRequired,
    incrementCounter: React.PropTypes.func.isRequired,
    decrementCounter: React.PropTypes.func.isRequired
};
// Стандартні значення
Comment.defaultProps = {
    name: 'Counter'
};

Існують ще деякі розбіжності, детальніше можна прочитати тут.

Незмінювані компоненти

Щоб створити компонент, який не взаємодіє зі станом, не потрібно навіть створювати клас. Ви можете створити його за допомогою функції, що приймає аргументом властивості. Так набагато простіше!

function CommentDisplay(props) {
  return <div>
            <div>{this.props.counterProp}</div>
        <br>
        <button onclick="{this.props.incrementCounter}">+</button>
        <button onclick="{this.props.decrementCounter}">-</button>
        </div>
}

Висновок

Ми розглянули базові принципи роботи з React. Цього вже достатньо щоб почати з ним працювати.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.9K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація