React.js. Начало работы. Часть 8 из 12

23.10.2019

Теги: JavaScriptReact.jsWeb-разработкаКомпонентСобытиеСписокФормаФреймворк

Создание приложения: планировщик задач

Приложение устроено предельно просто. Пользователь вводит текст задачи в поле ввода и жмет кнопку «Добавить». После отправки формы в списке задач появляется новый элемент. Для удаления элемента списка, достаточно кликнуть по нему мышью.

Создаем новое приложение

Итак, создаем новое приложение:

> 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-разработка • Список • Форма • Фреймворк • Событие • Компонент

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.