React.js. Начало работы. Часть 8 из 12
23.10.2019
Теги: JavaScript • React.js • Web-разработка • Компонент • Событие • Список • Форма • Фреймворк
Создание приложения: планировщик задач
Приложение устроено предельно просто. Пользователь вводит текст задачи в поле ввода и жмет кнопку «Добавить». После отправки формы в списке задач появляется новый элемент. Для удаления элемента списка, достаточно кликнуть по нему мышью.
Создаем новое приложение
Итак, создаем новое приложение:
> create-react-app todolist
Удаляем все файлы из директорий src
и public
. И создаем файл index.html
в директории public
:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Планировщик задач</title> </head> <body> <div id="container"></div> <body> </html>
В директории src
создаем файлы index.css
и index.js
:
body {
background: #77CCFF;
padding: 50px;
font-family: Arial, Helvetica, sans-serif;
}
#container {
display: flex;
justify-content: center;
}
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import TodoList from './TodoList'; ReactDOM.render( <div> <TodoList/> </div>, document.getElementById('container') );
Теперь создаем компонент TodoList
, который будет показывать форму:
import React, {Component} from 'react'; import './TodoList.css'; class TodoList extends Component { render() { return ( <div className="wrap"> <div className="form"> <form> <input placeholder="Новая задача" /> <button type="submit">Добавить</button> </form> </div> <div className="list"></div> </div> ); } } export default TodoList;
Для оформления формы и списка задач создадим файл TodoList.css
:
.wrap {
}
.wrap .form {
}
.wrap .form input {
padding: 10px;
}
.wrap .form button {
padding: 10px;
margin-left: 10px;
}
Чтобы проверить работу приложения, переходим в директорию todolist
и выполняем команду:
> npm start
Создаем новую задачу
Нужно добавить отслеживание события отправки формы и создать обработчик для этого события:
import React, {Component} from 'react'; import './TodoList.css'; class TodoList extends Component { constructor(props) { super(props); this.state = { items: [] } this.addItem = this.addItem.bind(this); } addItem(e) { var items = this.state.items; if (this._input.value !== '') { items.unshift({ key: Date.now(), text: this._input.value }); this.setState({ items: items }); this._input.value = ''; } e.preventDefault(); } render() { return ( <div className="wrap"> <div className="form"> <form onSubmit={this.addItem}> <input ref={(a) => this._input = a} placeholder="Новая задача" /> <button type="submit">Добавить</button> </form> </div> <div className="list"></div> </div> ); } } export default TodoList;
Показываем список задач
Для показа списка задач создадим еще один компонент TodoItems
:
import React, {Component} from 'react'; class TodoItems extends Component { constructor(props) { super(props); this.addItem = this.addItem.bind(this); } addItem(item) { return <li key={item.key}>{item.text}</li>; } render() { var items = this.props.items; var todoItems = items.map(this.addItem); return ( <ul> {todoItems} </ul> ); } } export default TodoItems;
import React, {Component} from 'react'; import './TodoList.css'; import TodoItems from './TodoItems'; class TodoList extends Component { constructor(props) { /* .......... */ } addItem(e) { /* .......... */ } render() { return ( <div className="wrap"> <div className="form"> .......... </div> <div className="list"> <TodoItems items={this.state.items} /> </div> </div> ); } } export default TodoList;
И добавим стилевое оформление для списка задач:
.wrap {
}
.wrap .form {
}
.wrap .form input {
padding: 10px;
}
.wrap .form button {
padding: 10px;
margin-left: 10px;
}
.wrap .list {
margin-top: 20px;
}
.wrap .list ul {
list-style: none;
padding-left: 0;
}
.wrap .list ul li {
margin-bottom: 10px;
background-color: rgba(255, 255, 255, 0.5);
padding: 10px;
border-radius: 5px;
}
Удаляем задачу из списка
Элементы, по которым планируется кликать мышкой для удаления, определяются в компоненте TodoItems
. А сами задачи мы храним в объекте state
компонента TodoList
. И нам необходимо как-то передавать данные между двумя компонентами.
Для начала назначим обработчик события click
:
class TodoItems extends Component { constructor(props) { super(props); this.addItem = this.addItem.bind(this); this.delete = this.delete.bind(this); } addItem(item) { return <li onClick={() => this.delete(item.key)} key={item.key}>{item.text}</li>; } delete(key) { this.props.delete(key); } render() { /* .......... */ } }
Функция delete()
фактически ничего не удаляет. Она лишь вызывает другую функцию, переданную в компонент через свойства. Теперь изменим компонент TodoList
:
import React, {Component} from 'react'; import './TodoList.css'; import TodoItems from './TodoItems'; class TodoList extends Component { constructor(props) { super(props); this.state = { items: [] } this.addItem = this.addItem.bind(this); this.deleteItem = this.deleteItem.bind(this); } addItem(e) { var items = this.state.items; if (this._input.value !== '') { items.unshift({ key: Date.now(), text: this._input.value }); this.setState({ items: items }); this._input.value = ''; } e.preventDefault(); } deleteItem(key) { var items = this.state.items; var filteredItems = items.filter( function(item) { return item.key !== key; } ); this.setState({ items: filteredItems }); } render() { return ( <div className="wrap"> <div className="form"> <form onSubmit={this.addItem}> <input ref={(a) => this._input = a} placeholder="Новая задача" /> <button type="submit">Добавить</button> </form> </div> <div className="list"> <TodoItems items={this.state.items} delete={this.deleteItem} /> </div> </div> ); } } export default TodoList;
Добавляем анимацию
Последняя задача — добавить некоторую анимацию, чтобы добавление и удаление элементов проходило естественнее. Для этого используем библиотеку Flip Movie, которую нужно добавить в проект. Для этого выполянем команду из директории todolist
:
> npm i -S react-flip-move
Импортируем библиотеку в проект и добавляем анимацию:
import React, {Component} from 'react'; import FlipMove from 'react-flip-move'; class TodoItems extends Component { constructor(props) { super(props); this.addItem = this.addItem.bind(this); this.delete = this.delete.bind(this); } addItem(item) { return <li onClick={() => this.delete(item.key)} key={item.key}>{item.text}</li>; } delete(key) { this.props.delete(key); } render() { var items = this.props.items; var todoItems = items.map(this.addItem) return ( <ul> <FlipMove duration={250} easing="ease-out"> {todoItems} </FlipMove> </ul> ); } } export default TodoItems;
Поиск: JavaScript • React.js • Web-разработка • Список • Форма • Фреймворк • Событие • Компонент