Я написал статью « Создание RESTful Web API с помощью Node.js и Express.js с нуля ». В этой статье была показана только часть API-интерфейса серверной части примера приложения со списком задач. Вы можете узнать больше об этом веб-API, перейдя по ссылке выше.

В этой статье я покажу вам, как создать одностраничное веб-приложение с помощью ReactJS. Итак, мы собираемся разработать приложение Todo, используя RESTful Web API, который я показал ранее. Можете считать эту статью частью-2.

Я также опубликовал и задокументировал этот веб-API на сайте heroku. Вы можете изучить его, перейдя по этой ссылке;
https://todowebapi.herokuapp.com

В этой статье предполагается, что у вас есть базовые знания JavaScript и возможности использования терминала.

Вы можете найти исходный код этого приложения в этом репозитории на github.

Мы будем использовать синтаксис javascript ES6, и нам нужно скомпилировать и связать наши исходные коды для распространения и запуска приложения. Это означает, что нам нужны такие инструменты, как babel и webpack, а также некоторые настройки. Но я думаю, что этот шаг слишком сложен, чтобы стать частью этой статьи. Позже я напишу новую статью об этом шаге, о котором упоминал выше. Теперь мы можем пропустить этот шаг.

Но как мы можем справиться с шагом, о котором мы говорили выше?

Если у вас нет опыта работы с этим этапом настройки, упомянутым выше, вы можете использовать набор инструментов «crate-react-app». Он создает для нас конвейер сборки внешнего интерфейса. Под капотом он использует babel и webpack, но вам пока не нужно о них ничего знать.

Приступим к созданию приложения.

Перед стартом

Если вы никогда не использовали Node.js или менеджер пакетов npm, вам следует установить их.

Вам не нужен Node.js для запуска приложения React, но для использования диспетчера пакетов npm вам понадобится установленный на вашем компьютере Node.js.

Чтобы проверить, установлен ли уже на вашем компьютере Node.js, откройте терминал и выполните команду «node -v». Если вы видите свою версию Node.js, она установлена. В противном случае перейдите по ссылке ниже.

Щелкните здесь, чтобы загрузить и установить Node.js (вы можете выбрать версию LTS)

И если у вас нет IDE или текстового редактора для написания javascript, я советую вам Visual Studio Code.

Щелкните здесь, чтобы загрузить VS Code (необязательно)

Создание проекта

Перейдите в корневую папку своей рабочей области и выполните команду ниже, чтобы создать новое приложение React;

npx crate-react-app todo-app-with-react-es6

Он создаст новое приложение для реагирования в вашей рабочей области с именем «todo-app-with-react-es6», а затем установит необходимые модули и пакеты.

Когда вы откроете папку «todo-app-with-react-es6» в своей любимой среде IDE, вы увидите начальную структуру проекта, включая некоторую разметку html и изображения.

Я собираюсь переопределить их и отредактировать файл «src/App.js», чтобы создать стартовую страницу нашего приложения.

Вот моя текущая структура папок после удаления некоторых ненужных файлов и ресурсов;

/todo-app-with-react-es6
|-- node_modules
|-- public
|   `-- index.html
|-- src
|   |-- App.js
|   |-- App.test.js
|   |-- index.css
|   |-- index.js
|   |-- serviceWorker.js
|   `-- setupTests.js
|-- .gitignore
|-- package.json
`-- README.md

А ниже достаточно html-разметки для нашего index.html файла.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Todo App with React and ES6</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

Мы начнем с небольшого начального кода экрана, чтобы упростить его, потому что наши файлы «App.js» и «index.css» пока выглядят так, как показано ниже.

import React from 'react';

class App extends React.Component {
  render() {
    return (
        <div className="app-container">
          <h1>Todo List</h1>
        </div>
    );
  }
}

export default App;

И файл «index.css»;

body {
    margin: 0;
}

.app-container {
    background-color: #282c34;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    color: white;
}
a {
    color: #fff;
    text-decoration: none;
}

a.selected {
    color: #DC143C
}

После редактирования вышеуказанных файлов откройте терминал в папке "todo-app-with-react-es6" и выполните команду «npm start».

Вы увидите только текст заголовка «Список задач». Не волнуйтесь, это ожидаемый результат :)

Получение предметов

Как гласит текст нашего заголовка, теперь нам нужно получить задачи из нашего веб-API.

Ответ нашего веб-API на элементы Todo выглядит так, как показано ниже.

[
    {"id": 1, "title": "Finalize project"},
    {"id": 2, "title": "Book ticket to London"},
    {"id": 3, "title": "Finish last article"},
    {"id": 4, "title": "Get a new t-shirt"},
    {"id": 5, "title": "Create dinner reservation"}
]

Мы внесем некоторые изменения в наш код «App.js», чтобы получать и перечислять элементы списка дел.

Я помещаю адрес героку, который я опубликовал и упоминал ранее, как URL-адрес веб-API. Но вы также можете запустить веб-api на своем локальном компьютере после клонирования или загрузки.

import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      items: []
    };

    this.todoApiUrl = 'https://todowebapi.herokuapp.com';
  }

  componentDidMount() {
    fetch(`${this.todoApiUrl}/items`)
      .then(response => response.json())
      .then(items => this.setState({items}));
  }

  render() {
    return (
        <div className="app-container">
          <h1>Todo List</h1>

          <ul>
            {
              this.state.items.map(item => <li key={item.id}>{item.title}</li>)
            }
          </ul>
        </div>
    );
  }
}

export default App;

В приведенном выше коде есть 3 важных момента.

Один из них - componentDidMount() метод, который вызывается после того, как компонент реакции готов. Официальные документы Reactjs говорят: «Если вам нужно загрузить данные с удаленной конечной точки, это хорошее место для создания экземпляра сетевого запроса». Мы получили это :)

Другой момент - это наш объект состояния, который вы видите внутри конструктора нашего класса Component. Он содержит данные, полученные с удаленной конечной точки. Обратите внимание на выражение «this.setState({items})» в последней связанной функции операции выборки. Это означает, что извлеченные элементы помещаются в объект состояния после завершения операции выборки.

И теперь у нас есть данные в объекте состояния, поэтому мы можем отобразить их на экране в методе render(). Вы можете передать свой шаблон компонента методу render(), как показано выше. Но, как видите, разметка компонента - это не просто HTML. Внутри фигурных скобок находится выражение javascript. Он называется JSX, что представляет собой специальный синтаксис для описания пользовательских интерфейсов реагирующих компонентов. Это не html и не javascript, но забавно :)

Каждый раз, когда вы вызываете функцию this.setState и обновляете объект состояния, представление компонента будет повторно визуализироваться с вашим новым объектом состояния.

Создание нового предмета

Итак, давайте добавим пару новых компонентов пользовательского интерфейса и дадим возможность пользователю создать новый элемент todo.

import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      items: [],
      title: ''
    };

    this.todoApiUrl = 'https://todowebapi.herokuapp.com';

    this.createNewItem = this.createNewItem.bind(this);
  }

  componentDidMount() {
    fetch(`${this.todoApiUrl}/items`)
      .then(response => response.json())
      .then(items => this.setState({items}));
  }

  createNewItem() {
    fetch(`${this.todoApiUrl}/items`, {
      method: "POST",
      headers: new Headers({'Content-Type': 'application/json; charset=utf-8'}),
      body: JSON.stringify({title: this.state.title})
    }).then(response => {
      if (!response.ok) {
        alert('An error occurred while creating new item');
      } else {
        return response.json();
      }
    }).then(createdItem => {
      this.setState(prevState => ({
        items: [...prevState.items, {id:createdItem.id, title: createdItem.title}],
        title: ''
      }));
    });
  }

  render() {
    return (
        <div className="app-container">
          <h1>Todo List</h1>

          <ul>
            {
              this.state.items.map(item => <li key={item.id}>{item.title}</li>)
            }
          </ul>

          <div>
            Title: <input type="text" value={this.state.title} onChange={(event) => this.setState({title: event.target.value})} />
            <button onClick={this.createNewItem}>Add New</button>
          </div>
        </div>
    );
  }
}

export default App;

Вы видите новый ввод html и кнопку управления внизу списка. Должно быть, ваше внимание привлекло то, что мы обрабатываем событие onchange элемента управления вводом html. Это способ реакции на получение текущего входного значения.

Эта встроенная функция обеспечивает сохранение входного значения в поле заголовка объекта состояния. Если вы хотите глубоко понять, как обрабатывать html-компоненты в reactjs, вы можете заглянуть в раздел Forms в официальных документах reactjs.

И у нас есть новая функция createNewItem(), которая отправляет запрос POST с новым заголовком элемента в веб-API. Мы вызываем эту функцию, когда нажимаем кнопку «Добавить».

Наш веб-API дает нам созданный объект элемента в качестве ответа сервера, если все в порядке. Затем мы помещаем успешно созданный элемент в объект состояния, чтобы убедиться, что он отображается на экране.

Обновление и удаление выбранного элемента

Теперь мы собираемся добавить новые функции для выбора, редактирования и удаления элементов. Последний исходный код "App.js" приведен ниже.

Мы помещаем новое поле «selectedItemId» в объект состояния, которое будет устанавливаться, когда вы щелкаете элемент на экране. И мы обернули каждый элемент интерактивной HTML-ссылкой, которая устанавливает поле «selectedItemId» с идентификатором выбранного элемента. И мы устанавливаем определенный класс css для выбранного элемента, чтобы выделить выбранный элемент. Это развитие делает элементы доступными для выбора на экране.

Как видите, функции «updateSelectedItem()» и «deleteSelectedItem()» очень похожи на функцию «createNewItem()», о которой мы говорили выше. Единственная разница в том, что у них есть собственный http-глагол в зависимости от того, что они делают.

Спасибо за ваше время и терпение.