Thành phần UploadPhoto xử lý yêu cầu tải ảnh lên blockchain Klaytn. Quy trình như sau:
Gọi phương pháp uploadPhoto của hợp đồng thông minh bằng cách gửi một giao dịch. Trong phương pháp hợp đồng uploadPhoto, một token ERC-721 mới được tạo.
Sau khi gửi một giao dịch, hãy cho thấy tiến trình cùng vòng đời giao dịch bằng thành phần Toast.
Khi giao dịch tiến vào một khối, hãy cập nhật PhotoData mới trong cửa hàng redux cục bộ.
Limiting content size
Kích thước tối đa của một giao dịch là 32KB. Do đó, chúng tôi hạn chế kích thước của dữ liệu đầu vào (ảnh và mô tả) không vượt quá 30KB để quá trình gửi đi diễn ra an toàn.
// src/components/UploadPhoto.jsimport React, { Component } from'react'import { connect } from'react-redux'import imageCompression from'utils/imageCompression';import ui from'utils/ui'import Input from'components/Input'import InputFile from'components/InputFile'import Textarea from'components/Textarea'import Button from'components/Button'import*as photoActions from'redux/actions/photos'import'./UploadPhoto.scss'// Đặt giới hạn nội dungconstMAX_IMAGE_SIZE=30*1024// 30KBconstMAX_IMAGE_SIZE_MB=30/1024// 30KBclassUploadPhotoextendsComponent { state = { file:'', fileName:'', location:'', caption:'', warningMessage:'', isCompressing:false, }handleInputChange= (e) => {this.setState({ [e.target.name]:e.target.value, }) }handleFileChange= (e) => {constfile=e.target.files[0]/** * Nếu kích thước ảnh lớn hơn MAX_IMAGE_SIZE(30KB), * Nén ảnh để tải trên giao dịch * cf. Kích thước dữ liệu đầu vào giao dịch tối đa: 32KB */if (file.size >MAX_IMAGE_SIZE) {this.setState({ isCompressing:true, })returnthis.compressImage(file) }returnthis.setState({ file, fileName:file.name, }) }handleSubmit= (e) => {e.preventDefault()const { file,fileName,location,caption } =this.statethis.props.uploadPhoto(file, fileName, location, caption)ui.hideModal() }compressImage=async (imageFile) => {try {constcompressedFile=awaitimageCompression(imageFile,MAX_IMAGE_SIZE_MB)this.setState({ isCompressing:false, file: compressedFile, fileName:compressedFile.name, }) } catch (error) {this.setState({ isCompressing:false, warningMessage:'* Nén ảnh không thành công' }) } }render() {const { fileName,location,caption,isCompressing,warningMessage } =this.statereturn ( <formclassName="UploadPhoto"onSubmit={this.handleSubmit}> <InputFileclassName="UploadPhoto__file"name="file"label="Search file"fileName={isCompressing ?"Đang nén ảnh...": fileName}onChange={this.handleFileChange}err={warningMessage}accept=".png, .jpg, .jpeg"required /> <InputclassName="UploadPhoto__location"name="location"label="Location"value={location}onChange={this.handleInputChange}placeholder="Bạn đã chụp ảnh này ở đâu?"required /> <TextareaclassName="UploadPhoto__caption"name="caption"value={caption}label="Caption"onChange={this.handleInputChange}placeholder="Upload your memories"required /> <ButtonclassName="UploadPhoto__upload"type="submit"title="Upload" /> </form> ) }}constmapDispatchToProps= (dispatch) => ({uploadPhoto: (file, fileName, location, caption) =>dispatch(photoActions.uploadPhoto(file, fileName, location, caption)),})exportdefaultconnect(null, mapDispatchToProps)(UploadPhoto)
3) Tương tác với hợp đồng
Hãy tạo một hàm để viết dữ liệu ảnh lên Klaytn. Send transaction to contract: uploadPhoto
Không giống các lệnh gọi hàm Read-only, việc viết dữ liệu làm phát sinh phí giao dịch. Phí giao dịch được xác định bằng lượng gas đã sử dụng. gas là đơn vị đo thể hiện số lượng phép tính cần để xử lý giao dịch.
Vì những lý do này, việc gửi một giao dịch cần hai thuộc tính from và gas.
Chuyển đổi tập tin ảnh thành một chuỗi byte để tải trên giao dịch
(Trong Klaystagram contract, chúng ta đã định nghĩa định dạng ảnh là byte trong cấu trúc PhotoData)
Đọc dữ liệu ảnh dưới dạng ArrayBuffer bằng FileReader
Chuyển đổi ArrayBuffer thành chuỗi số hex
Thêm tiền tố 0x để thỏa mãn định dạng byte
Gọi phương pháp hợp đồng: uploadPhoto
from: Một tài khoản gửi giao dịch này và thanh toán phí giao dịch.
gas: Lượng gas tối đa mà tài khoản from sẵn sàng thanh toán cho giao dịch này.
Sau khi gửi giao dịch, hiển thị tiến trình cùng vòng đời giao dịch bằng thành phần Toast.
Nếu giao dịch thành công tiến vào một khối, gọi hàm updateFeed để thêm ảnh mới vào trang nguồn cấp dữ liệu.
// src/redux/actions/photo.jsexportconstuploadPhoto= ( file, fileName, location, caption) => (dispatch) => {// 1. Chuyển đổi tập tin ảnh thành chuỗi số hex để tải trên giao dịchconstreader=newwindow.FileReader()reader.readAsArrayBuffer(file)reader.onloadend= () => {constbuffer=Buffer.from(reader.result)// Thêm tiền tố "0x" vào hexString để hợp đồng nhận diện hexString là byteconsthexString="0x"+buffer.toString('hex')// 2. Gọi phương pháp hợp đồng: uploadPhoto// Gửi giao dịch với tập tin ảnh (hexString) và mô tảtry{KlaystagramContract.methods.uploadPhoto(hexString, fileName, location, caption).send({ from:getWallet().address, gas:'200000000', }, (error, txHash) => {if (error) throw error;// 3. Sau khi gửi giao dịch,// hiển thị tiến trình cùng vòng đời giao dịch bằng thành phần "Toast".ui.showToast({ trạng thái:'đang chờ', message:`Gửi một giao dịch... (uploadPhoto)`, txHash, }) }).then((receipt) => {ui.showToast({ trạng thái:receipt.trạng thái ?'success':'fail', message:`Đã nhận biên lai! Điều đó nghĩa là giao dịch của bạn ở trong khối klaytn (#${receipt.blockNumber}) (uploadPhoto)`, link:receipt.transactionHash, })// 4. Nếu giao dịch của bạn thành công tiến vào một khối,// gọi hàm "updateFeed" để thêm ảnh mới vào trang nguồn cấp dữ liệu.if(receipt.trạng thái) {consttokenId=receipt.events.PhotoUploaded.returnValues[0]dispatch(updateFeed(tokenId)) } }) } catch (error) {ui.showToast({ trạng thái:'error', message:error.toString(), }) } }}
cf) Vòng đời giao dịch
Sau khi gửi giao dịch, bạn có thể lấy vòng đời giao dịch (transactionHash, receipt, error).
Sau khi phiên bản giao dịch đã ký của bạn được xây dựng đúng cách, sự kiện transactionHash sẽ được kích hoạt. Bạn có thể lấy hàm băm của giao dịch trước khi gửi giao dịch lên mạng lưới.
Sự kiện receipt sẽ được kích hoạt khi bạn nhận được biên lai giao dịch. Điều đó nghĩa là giao dịch của bạn ở trong một khối. Bạn có thể xem số khối bằng receipt.blockNumber.
Sự kiện error được kích hoạt khi có lỗi xảy ra.
4. Tải ảnh lên trang nguồn cấp dữ liệu: updateFeed
Sau khi thành công gửi giao dịch vào hợp đồng, FeedPage cần được cập nhật.
Để cập nhật nguồn cấp dữ liệu ảnh, ta cần lấy dữ liệu ảnh mới ta vừa tải lên. Hãy gọi getPhoto() bằng tokenId. tokenId có thể được truy xuất từ biên lai giao dịch. Sau đó, thêm dữ liệu ảnh mới vào cửa hàng redux cục bộ.
// src/redux/actions/photo.js/** * 1. Gọi phương pháp hợp đồng: getPhoto() * Để lấy dữ liệu ảnh mới ta vừa tải lên, * gọi hàm "getPhoto()" bằng tokenId từ biên lai sau khi gửi giao dịch*/constupdateFeed= (tokenId) => (dispatch, getState) => {KlaystagramContract.methods.getPhoto(tokenId).call().then((newPhoto) => {const { photos: { feed } } =getState()constnewFeed= [feedParser(newPhoto),...feed]// 2. cập nhật nguồn cấp dữ liệu mới vào cửa hàngdispatch(setFeed(newFeed)) })}