用 React + Rails + GraphQL 构建图像上传功能!
最开始
我最近也开始接触React,为了学习的需要
- React + Rails + GraphQL
我正在制作一个个人SPA应用程序!所以,这次我想尝试创建一个图片上传功能!
关于使用的物品,简单作说明。
-
- Ruby on Rails (バックエンド)
-
- React(フロントエンド)
-
- TypeScript
-
- GraphQL
- Apollo
实施
后端
为了上传图像,需要安装以下的Gem。
# Gemfile
gem 'carrierwave'
gem 'carrierwave-base64'
-
- モデルファイルにアップローダーを指定する記述を追加
以下の記述だけでbase64で渡ってきたデータを画像として保存してくれる…!
# Item.rb
class Item < ApplicationRecord
mount_base64_uploader :image, ItemImageUploader <- これを追加
end
如果你不了解CarrierWave,请自行搜索了解。
在Resolver中接收参数值并保存
# app/graphql/mutations/create_item.rb
module Mutations
class CreateItem < Mutations::BaseMutation
argument :params, InputTypes::Item, required: true <- 引数用のTypeファイル
field :item, ObjectTypes::Item, null: false
def resolve(params:)
item = Item.create!(params.to_h)
{item: item}
rescue => e
GraphQL::ExecutionError.new(e.message)
end
end
end
# app/graphql/input_types/item.rb(引数用Typeファイル)
module InputTypes
class Item < Types::BaseInputObject
graphql_name 'ItemAttributes'
argument :image, String, required: false <- 追加
end
end
前端
创建用于选择图像的表单
- inputタグ追加(type=”file”でファイル選択フォームに)
<input
name="file"
type="file"
accept="image/png"
/>
使用useState,在状态中添加管理选择图像的state。
import { useState } from "react";
const [image, setImage] = useState<string | undefined>(undefined)
在选择图片时,添加一个函数将图片数据设置到上述的image state中。
使用readAsDataURL函数,将图片转换为base64格式(将图片转换为字符串)!
※ 由于GraphQL只能处理JSON格式的数据,无法处理二进制数据,因此需要转换为字符串!
const onChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files
if (files && files[0]) {
const reader = new FileReader()
reader.readAsDataURL(files[0])
reader.onload = function() {
var image: any
image = reader.result;
setImage(image); <- image stateに画像をセット
}
}
}
- inputタグで、画像セット時に↑の関数を呼び出して、選択画像をimage stateにセットする
<input
name="file"
type="file"
accept="image/png"
onChange={onChangeFile} <- 追加
/>
- 以下のように、image stateを、imgタグのsrcにセットすると選択中の画像が確認できるかとおもいます!
<img src={image} />
只需要将图像数据传递给Mutation的参数即可。
const [createItem] = useCreateItemMutation();
createItem({ variables: { params: { image: image } } });
感谢您阅读本文,并提供实现的一个例子!