В этом сообщении в блоге я расскажу, как интегрировать систему загрузки изображений в приложение React. Я хотел провести это пошаговое руководство, потому что мне пришлось создать подобную систему в приложении стека MERN, которое я создаю, и я не понимал, что загрузка изображений с локального компьютера в базу данных для отображения во внешнем интерфейсе нашего приложения будет довольно сложной задачей. каким бы сложным оно ни было, так что надеюсь, те из вас, кто хочет создать такую ​​же функциональность, сочтут эту элементарную демонстрацию полезной!

Это очень простое приложение, созданное с использованием Node.js, Express.js и React.js, будет иметь три основные функции:

  1. Форма для загрузки изображений.
  2. Способ предварительного просмотра изображения перед загрузкой.
  3. Контейнер, содержащий все загруженные изображения.

Перво-наперво я создал каталог для проекта. Убедитесь, что у вас установлены node и npm для сборки этого проекта. Вы можете убедиться в этом с помощью следующих команд.

Если они установлены, перейдите в каталог своего проекта и запустите npm init и заполните формы по мере необходимости / в соответствии с вашими личными предпочтениями. Это создаст файл package.json, в котором мы будем хранить наши скрипты и наши зависимости. Для этого проекта я установил 5 пакетов, 3 из которых абсолютно необходимы для наших целей. Я предоставил ссылки на документацию по каждой из следующих зависимостей.

  1. Https://expressjs.com
  2. Https://www.npmjs.com/package/concurrently
  3. Https://www.npmjs.com/package/nodemon
  4. Https://www.npmjs.com/package/multer
  5. Https://www.npmjs.com/package/cors

После установки давайте создадим наш сервер. Сначала мы создаем наше экспресс-приложение и сразу же вызываем cors в нашем экспресс-приложении. Cors означает Cross-Origin-Resource-Sharing и позволяет нам извлекать данные из другого домена, который не является доменом, в котором мы сейчас находимся. Как видите, я запустил свое приложение на порту 3200. Когда мы создаем наше приложение для реагирования на следующем этапе, порт приложения для реагирования по умолчанию имеет порт 3000, и поскольку мы собираемся получать изображения из нашего внутреннего API (внешнего домена - порт 3200), нам нужно установить и использовать cors, чтобы наше приложение принимало запросы от localhost: 3000.

Nodemon - отличный пакет для установки, поскольку мы можем запускать наш сервер, а nodemon следит за обновлениями в нашем коде по мере их создания. В нашем файле package.json я создал сценарий для запуска nodemon с помощью простой команды npm run server. Как вы можете видеть, npm run start запускает сервер узлов, но при запуске сервера nom run запускается nodemon, что позволяет нам видеть обновления на нашем сервере в реальном времени.

Когда мы запускаем npm run server в терминале, мы видим вот что.

Мы должны увидеть запуск nodemon вместе с вызовом node server.js (server.js - это имя файла, в котором мы создали экспресс-приложение - файла, через который мы прошли). Мы также должны увидеть журнал консоли в нашей функции app.listen в строке 12, который также показывает нам, на каком порту в настоящее время работает наш сервер.

В строке 8 мы создаем наш первый маршрут (в данном случае с нашим текущим портом этот маршрут будет http: // localhost: 3200 /). Если наш сервер работает, и мы делаем http-запрос на этот URL-адрес из нашего браузера, мы должны увидеть данные ответа JSON в окне.

В строке 10 мы настраиваем корневой каталог статических файлов с помощью встроенной статической функции промежуточного программного обеспечения Express, которая позволяет нам загружать и обслуживать статические файлы с нашего сервера. В каталоге с именем uploads мы будем хранить загруженные файлы изображений. В строке 12 мы объявляем наш маршрут, по которому наш сервер может получать запросы. Как видите, где происходит импорт модуля по пути «routes / api / images». Я строю свои маршруты таким образом, как условность. Сначала я создаю каталог с именем routes, в котором я создаю каталог с именем api, а внутри api я создаю все свои файлы, в которых объявляю маршруты в соответствии, возможно, с моделями, коллекциями или таблицами. В данном случае нас интересует только загрузка и отображение изображений, поэтому я создал файл с именем images, в котором мы будем использовать два действия: GET для получения всех изображений и POST для создания изображений.

В этом примере мы не используем никакую базу данных для хранения. Мы просто сохраняем и извлекаем файлы из папки под названием uploads. В нашем первом маршруте я использую встроенный метод маршрутизатора express, чтобы выполнить действие GET для наших изображений. Если бы мы сделали запрос по адресу «http: // localhost: 3200 / api / images»), мы бы увидели JSON с ключевыми файлами, которые содержат массив наших файлов изображений! Если папка для загрузок пуста, мы получим сообщение «Изображения не загружены!».

Теперь приступим к настройке мультера. В первой цитате Multer с сайта npmjs.com: Multer - это промежуточное программное обеспечение node.js для обработки multipart / form-data, которое в основном используется для загрузки файлов. Multer - замечательный пакет, который позволяет нам отслеживать, размещать и управлять файлами, когда они поступают на наш сервер. Вернувшись в наш файл маршрута для изображений, давайте настроим multer.

Сначала мы должны импортировать файл multer. Затем мы используем встроенную функцию diskStorage от Multer и передаем объект, внутри которого мы можем делать множество вещей, помещая наши файлы по мере их загрузки в конкретный каталог, переименовывать файл и даже проверять правильность файла. тип файла и / или меньше определенного размера. В нашем случае мы сохраняем папки в наш каталог загрузок (убедитесь, что у вас действительно есть каталог с именем uploads в корне вашего приложения - multer, хоть и волшебный, но не сделает его за вас!), Объявляя место назначения key, равный функции, которая содержит обратный вызов, а второй аргумент этого обратного вызова - это место, где мы храним имя каталога. В нашем ключе имени файла мы устанавливаем его имя файла, равное ключу originalname для объекта файла, поскольку он идет с ключевым исходным именем, которое содержит имя файла, которое было у файла до загрузки. После сохранения метода multer, вызываемого с нашим объектом хранилища в качестве аргумента, в виде объекта с именем uploads, теперь мы можем передать объект uploads в качестве промежуточного программного обеспечения на любом из наших маршрутов.

Наш метод публикации изображений очень прост. В этом методе мы ожидаем одно изображение, поэтому мы вызываем единственный метод из объекта загрузки, и мы будем следить за ключевым «изображением», которое будет иметь значение изображения. Как часть наших составных данных формы, которые мы получаем в бэкэнде, изображение будет сохранено в req.file, а путь к изображению будет req.file.path. Наш файл после запроса на публикацию будет сохранен в каталоге загрузок, и мы отправим сообщение JSON с сервера, чтобы указать, что загрузка прошла успешно. В этом файле мы можем выполнять асинхронные действия, такие как сохранение данных в базе данных, но для наших целей нам нужно только хранить файлы в каталоге загрузок.

Я рекомендую протестировать наши маршруты получения и отправки, например, в почтальоне и убедиться, что они работают, прежде чем мы интегрируем наш интерфейс. Для почтового маршрута в Postman мы хотим сделать почтовый запрос на http: // localhost: 3200 / api / images и дать ему заголовок Content-Type: multipart / form-data. . В теле загрузим наш файл с изображением ключа. Если все пойдет хорошо, мы должны увидеть сообщение об успешном завершении в терминале Postman!

ФРОНТЕНД

В приложение React. * ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я ИСПОЛЬЗОВАЛ 0 CSS, поэтому заранее извиняюсь за появление визуальных эффектов *. Я начал с создания приложения для реагирования в нашем корневом каталоге под названием client, и удалил много вещей, которые нам не понадобятся для этого конкретного проекта, таких как сервис-воркеры, логотип и другие файлы. После того, как приложение React настроено, позвольте cd перейти в каталог нашего приложения React и установить пакет axios, который я предпочитаю использовать для выборки и отправки данных (хотя вы действительно можете использовать любой метод, который вам больше нравится). После установки axios, давайте начнем одновременно из нашего корневого каталога. Concurrently - это замечательный пакет, который позволяет запускать серверы одновременно с помощью одной команды. В файле package.json корневого каталога мы хотим создать сценарии, которые позволят нам делать это, используя как таковые одновременно.

Во-первых, я добавил команду сценария под названием «client», если мы запустим npm run client, она запустит наше приложение для реагирования. За флагом префикса следует имя каталога нашего приложения реакции. Теперь с помощью команды dev мы используем одновременно для запуска нашего сервера с nodemon и приложением реакции одновременно, поэтому порты 3200 и 3000 будут работать одновременно из одного окна терминала!

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

1.) ImageContainer - получение изображений с нашего сервера и отображение

2.) ImageForm - форма для загрузки и просмотра изображений на наш сервер

Еще одна важная часть логики, которую я добавил, - это то, что я буду называть своего рода слушателем состояния нашего компонента приложения для загрузки новых изображений, метко названного newImage. Каждый раз, когда мы отправляем новое изображение для загрузки, мы вызываем setNewImage и добавляем строку, которая просто говорит «New Image» в состояние нашего массива newImage. Мы делаем это, чтобы уведомить наш ImageContainer, когда нужно обновить и сделать новый запрос GET. Я применил этот хакерский метод обновления состояния, так как я не настраиваю redux или не использую React Context API для этого проекта, и в основном хотел простое, быстрое (хотя и неуклюжее) исправление для демонстрации загрузки изображений!

В ImageContainer мы будем делать GET-запрос к серверу для получения изображения. Если наши файлы, наш массив является правдивым (например, он содержит изображения), мы будем хранить наши изображения в состоянии; в противном случае наши данные ответа будут содержать наше сообщение «Изображения не загружены!», как мы настроили в серверной части, и мы установим его в состоянии. Наша функция getImages вызывается после монтирования и выполнения обновлений, что, возможно, не самый эффективный способ получения наших изображений, поскольку мы извлекаем их все при каждом повторном рендеринге, но для наших целей это подойдет. теперь. (Для более оптимальной конфигурации мы могли бы создать маршрут, который извлекает все изображения при подключении компонентов, а затем прослушивает последние загруженные изображения, а затем добавляет их в наше состояние в качестве обновления). В нашем useEffect мы используем опору newImage из нашего родительского компонента приложения в качестве зависимости, давая команду, что всякий раз, когда будет выполнено обновление нашей опоры newImage, делать новый запрос на получение для нашего внутреннего API.

Внутри оператора return мы используем тернарную операцию для условного рендеринга изображений, если они существуют. Если они этого не сделают, мы покажем наш запасной вариант; если они это сделают, мы будем перебирать наш массив изображений и отображать каждое изображение. В нашем методе настройки изображения мы используем URL-адрес нашего сервера http: // localhost: 3200 / «и имя файла в том виде, в каком оно сохранено в нашем сервере, чтобы получить доступ к изображению и отобразить его! Я решил сделать объявление URL нашего сервера модульным как API_URL, потому что мы собираемся использовать его в нескольких компонентах, поэтому я хотел, чтобы наш код был более СУХИМ.

Если мы запустим наше приложение для реагирования, мы увидим откат, поскольку я лично еще не загружал никаких фотографий! Теперь пора создать эту форму в нашем компоненте ImageForm.

В нашем компоненте ImageForm мы хотим завершить логику для двух других целей, упомянутых в начале этого поста: предварительный просмотр изображений, а затем фактическая отправка загрузок на наш сервер.

В операторе return для нашего компонента ImageForm мы условно визуализируем форму или предварительный просмотр нашего изображения, если оно действительно загружено. Наш тип ввода - файл, и он принимает только png, jpg или jpeg. Когда мы загружаем файл, он вызывает метод handleImageUpload нашего объекта onChange. В handleImageUpload мы устанавливаем состояние нашего изображения равным e.target.files [0]. e.target.files содержит список всех файлов, которые мы добавили в нашу форму, и, поскольку нам нужен первый, мы сохраняем только первый индекс, который представляет собой объект, содержащий необходимую информацию. Мы также хотим установить для Preview значение true, чтобы отобразить предварительный просмотр выбранного нами изображения. В нашем окне предварительного просмотра есть кнопка, которая очищает изображение и отображает его. Мы отображаем изображение, используя метод createObjectURL объекта URL и вызывая его с изображением, переданным в качестве аргумента. Если мы отправим изображение, нажав Загрузить! Он должен очистить форму, установить для предварительного просмотра значение false и передать наше изображение в метод uploadAction, который я перенес в другой файл. И последнее, но не менее важное: мы вызываем handleNewImage, который является опорой, которую мы передали из нашего компонента приложения, которая добавляет новую строку в наше состояние newImage.

Ниже приведен метод uploadAction, в котором мы берем наше изображение и добавляем его для формирования данных, которые мы передаем как наш почтовый запрос в axios в качестве тела.

Допустим, я добавляю изображение под названием broccoli.jpg, которое таинственным образом сохранило на своем рабочем столе. После загрузки я должен увидеть это:

Теперь, когда изображение находится в состоянии изображения нашего ImageForm, мы должны увидеть его предварительный просмотр. В правом верхнем углу есть кнопка для очистки предварительного просмотра, а в правом нижнем углу есть кнопка для загрузки. Если я нажму кнопку загрузки, мы увидим вот что. Мы должны снова увидеть отображение нашей формы, но теперь брокколи отображается в нашем контейнере изображений - даже если мы обновим страницу!

И вуаля! Очень простая демонстрация загрузки и отображения изображений в приложении с полным стеком и полностью на JavaScript с использованием node.js, express.js и React !!