I am using the ant design uploader to show the user profile picture in the dashboard page, In case a picture is not there in the database, then it must show the default upload button instead.
Below is an example ant design provides, how would I implement the login I've mentioned above.
import { Upload, message } from 'antd';
import { LoadingOutlined, PlusOutlined } from '#ant-design/icons';
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
function beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('You can only upload JPG/PNG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
}
class Avatar extends React.Component {
state = {
loading: false,
};
handleChange = info => {
if (info.file.status === 'uploading') {
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl =>
this.setState({
imageUrl,
loading: false,
}),
);
}
};
render() {
const { loading, imageUrl } = this.state;
const uploadButton = (
<div>
{loading ? <LoadingOutlined /> : <PlusOutlined />}
<div style={{ marginTop: 8 }}>Upload</div>
</div>
);
return (
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
beforeUpload={beforeUpload}
onChange={this.handleChange}
>
{imageUrl ? <img src={imageUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
</Upload>
);
}
}
ReactDOM.render(<Avatar />, mountNode);
Related
How can I use Upload component in Ant Design to upload avatar to Firebase?
Here is what I used and tried in React:
// Modal hook
const [modal1Open, setModal1Open] = useState(false);
// Upload new avatar
const [loading, setLoading] = useState(false);
const [imageUrl, setImageUrl] = useState();
const handleAvatarChange = (info) => {
if (info.file.status === 'uploading') {
setLoading(true);
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, (url) => {
setLoading(false);
setImageUrl(url);
});
}
};
const uploadAvatar2fb = async () => {
console.log('new avatar url: ', imageUrl)
try {
await addAvatarUrl2UserDb(location.state.userEmail, imageUrl)
} catch (error) {
console.log(error.message)
}
}
const uploadButton = (
<div>
{loading ? <LoadingOutlined /> : <PlusOutlined />}
<div
style={{
marginTop: 8,
}}
>
Upload
</div>
</div>
);
return (
{/* change avatar */}
<Button type="primary" onClick={() => setModal1Open(true)}>Change Avatar</Button>
<Modal
title="Upload your new avatar here"
centered
open={modal1Open}
onOk={() => setModal1Open(false)}
onCancel={() => setModal1Open(false)} >
<p>Click below to upload...</p>
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
// upload address
action='./images/'
// check format jpg/png check size < 2mb
beforeUpload={beforeUpload}
// set new upload url
onChange={handleAvatarChange} >
{imageUrl ? (
<img
src={imageUrl}
alt="avatar"
style={{
width: '100%',
}}
/>
) : (
uploadButton
)}
</Upload>
</Modal>
)
How do I handle with the action='' in that <Upload ..> tag?
I wrote this trying to make the uploading to firebase
const uploadAvatar2fb = async () => {
console.log('new avatar url: ', imageUrl)
try {
await addAvatarUrl2UserDb(location.state.userEmail, imageUrl)
} catch (error) {
console.log(error.message)
}
}
which called the function in firebase.js
// save avart to users
export const addAvatarUrl2UserDb = async (email, url) => {
const userDocRef = doc(db, 'users', email)
try {
await setDoc(userDocRef, {
avatar: url
})
} catch (error) {
console.log("avatar url upload error:", error.message)
}
}
And when I tried to upload after start npm, I got the error like POST http:localhost:3000/{url of the action} 404 not found. It shows that the address I wrote in <Upload action='...' /> is not found.
How could I solve this and make the uploading works?
I'm new to React and I want to use Antdesign for image upload, but the component class component given in ant design's site. How can I convert the code below into a functional component?
in what way can i do this? Or is there any online tool that can do this?
here is my code :
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
function beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('You can only upload JPG/PNG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
}
class Avatar extends React.Component {
state = {
loading: false,
};
handleChange = info => {
if (info.file.status === 'uploading') {
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl =>
this.setState({
imageUrl,
loading: false,
}),
);
}
};
render() {
const { loading, imageUrl } = this.state;
const uploadButton = (
<div>
{loading ? <LoadingOutlined /> : <PlusOutlined />}
<div style={{ marginTop: 8 }}>Upload</div>
</div>
);
return (
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
beforeUpload={beforeUpload}
onChange={this.handleChange}
>
{imageUrl ? <img src={imageUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
</Upload>
);
}
}
ReactDOM.render(<Avatar />, mountNode);
You will need to replace your class with a function that returns a JSX element.
You'll need to refactor your state to use the useState hook: https://reactjs.org/docs/hooks-state.html
DigitalOcean has a nice guide here: https://www.digitalocean.com/community/tutorials/five-ways-to-convert-react-class-components-to-functional-components-with-react-hooks
It will end up looking something like the following:
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener("load", () => callback(reader.result));
reader.readAsDataURL(img);
}
function beforeUpload(file) {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
if (!isJpgOrPng) {
message.error("You can only upload JPG/PNG file!");
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error("Image must smaller than 2MB!");
}
return isJpgOrPng && isLt2M;
}
function Avatar() {
const [imageUrl, setImageUrl] = useState(null);
const [loading, setLoading] = useState(false);
const handleChange = (info) => {
if (info.file.status === "uploading") {
setLoading(true)
return;
}
if (info.file.status === "done") {
// Get this url from response in real world.
getBase64(info.file.originFileObj, (imageUrl) => {
setImageUrl(imageUrl);
setLoading(false);
});
}
};
const uploadButton = (
<div>
{loading ? <LoadingOutlined /> : <PlusOutlined />}
<div style={{ marginTop: 8 }}>Upload</div>
</div>
);
return (
<Upload
name="avatar"
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
beforeUpload={beforeUpload}
onChange={handleChange}
>
{imageUrl ? (
<img src={imageUrl} alt="avatar" style={{ width: "100%" }} />
) : (
uploadButton
)}
</Upload>
);
};
I have an upload component from ant design library.
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import {
Form,
Select,
InputNumber,
Switch,
Radio,
Slider,
Button,
Upload,
Rate,
Checkbox,
Row,
Col,
} from 'antd';
import { UploadOutlined, InboxOutlined } from '#ant-design/icons';
const { Option } = Select;
const formItemLayout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 14,
},
};
const normFile = e => {
console.log('Upload event:', e);
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
};
const Demo = () => {
const onFinish = values => {
console.log('Received values of form: ', values);
};
const [state, setState] = useState({
loading: false,
});
function getBase64(img, callback) {
const reader = new FileReader();
reader.addEventListener('load', () => callback(reader.result));
reader.readAsDataURL(img);
}
const handleChange = info => {
if (info.file.status === 'uploading') {
setState({loading: true});
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
getBase64(info.file.originFileObj, imageUrl =>
setState({
imageUrl,
loading: false,
}),
);
}
};
function beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
console.error('You can only upload JPG/PNG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
console.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
}
const uploadButton = (
<div>
<div className="ant-upload-text">Upload img</div>
</div>
);
const {imageUrl} = state;
return (
<Form
name="validate_other"
{...formItemLayout}
onFinish={onFinish}
initialValues={{
'input-number': 3,
'checkbox-group': ['A', 'B'],
rate: 3.5,
}}
>
<Form.Item
name="upload"
label="Upload"
valuePropName="fileList"
getValueFromEvent={normFile}
>
<Upload
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
beforeUpload={beforeUpload}
onChange={handleChange}
>
{imageUrl ? <img src={imageUrl} alt="avatar" style={{width: '100%'}}/> : uploadButton}
</Upload>
</Form.Item>
<Form.Item
wrapperCol={{
span: 12,
offset: 6,
}}
>
<Button type="primary" htmlType="submit">
get data from upload
</Button>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
Now i have an issue when i upload an image and after that click on upload img button. I don't get the base 64 data of image in console.log('Received values of form: ', values);
Question: How, when i will click on that button to get data as base64?demo: https://codesandbox.io/s/silent-grass-sqzl1?file=/index.js:0-2944
Ok so i have an MERN app (CRA) and photo upload. Everything works great but when i will do npm run build i cant send photo (over 1MB) to backend. I've used postman to test and again worked great :). In development mode its working. Something is blocking requests from frontend when i want to upload photos. I've checked logs with morgan and it shows that this request with large photo upload didnt happen. Im using axios to communicate with backend and express file upload but backend works well. I dont know what is blocking my photos. Also express file upload in debuging mode is telling that "Request is not eligible for upload!"
action in redux:
export const addGalleryPhoto = (file) => async (dispatch) => {
const config = {
headers: {
"Content-Type": "multipart/form-data",
},
};
try {
await axios.put(`/api/v1/config/uploadGalleryPhoto`, file, config);
dispatch(getPhotos());
} catch (err) {
const errors = err.response.data.error.split(",");
if (errors) {
errors.forEach((error) => dispatch(setAlert(error, "error")));
}
dispatch({ LOAD_PHOTOS_FAILED });
}
};
controller in node:
exports.uploadGalleryPhoto = asyncHandler(async (req, res, next) => {
if (!req.files) {
return next(new ErrorResponse(`Dodaj plik`, 400));
}
const file = req.files.file;
// Make sure the image is a photo
if (!file.mimetype.startsWith("image")) {
return next(new ErrorResponse(`Możesz wysłać tylko zdjęcia`, 400));
}
if (file.size > process.env.MAX_FILE_UPLOAD) {
return next(
new ErrorResponse(
`Zbyt duże zdjęcie. Maksymalny rozmiar pliku: ${Math.round(
process.env.MAX_FILE_UPLOAD / 1024
)} MB`,
400
)
);
}
file.name = `photo_${uuid()}${path.parse(file.name).ext}`;
file.mv(`${process.env.FILE_UPLOAD_PATH}/${file.name}`, async (err) => {
if (err) {
console.error(err);
return next(new ErrorResponse(`Problem with file upload`, 500));
}
const config = await Config.find();
await Config.findByIdAndUpdate(config[0].id, {
galleryPhotos: [...config[0].galleryPhotos, file.name],
});
res.status(200).json({
success: true,
data: file.name,
});
});
});
Gallery component:
import React, { useEffect, useState, useRef, Fragment } from "react";
import PropTypes from "prop-types";
import { Card, Modal, Button } from "antd";
import { DeleteOutlined } from "#ant-design/icons";
import Spinner from "./../layout/Spinner";
import { connect } from "react-redux";
import {
addGalleryPhoto,
getPhotos,
deletePhoto
} from "./../../store/actions/gallery";
const AdminGallery = ({ photos, addGalleryPhoto, getPhotos, deletePhoto }) => {
useEffect(() => {
getPhotos();
}, [getPhotos]);
const fileInput = useRef();
const [value, setValue] = useState("");
const [formData, setFormData] = useState({
deleteVisible: false,
photo: null
});
const onSubmit = e => {
e.preventDefault();
const formData = new FormData();
formData.append("file", value);
addGalleryPhoto(formData);
setValue("");
};
if (photos.loading || photos.photos.null) {
return <Spinner />;
} else {
return (
<Fragment>
<div className="admin-gallery">
<div>
<input
type="file"
style={{ display: "none" }}
ref={fileInput}
onChange={e => setValue(e.target.files[0])}
/>
{value === "" ? (
<button
type="button"
className="btn btn--primary"
onClick={e => fileInput.current.click()}
>
Dodaj plik
</button>
) : (
<button
type="button"
className="btn btn--primary"
onClick={e => onSubmit(e)}
>
Wyślij zdjęcie
</button>
)}
<div>
{photos.photos.length === 0 ? (
<div className="no-content">Brak Zdjęć</div>
) : (
<div className="admin-gallery__photo-wrapper">
{photos.photos.map(item => {
return (
<Card
style={{ padding: "0 !important" }}
key={item}
actions={[
<DeleteOutlined
onClick={() =>
setFormData({
...formData,
deleteVisible: true,
photo: item
})
}
/>
]}
>
<img
className="admin-gallery__photo"
src={`${process.env.PUBLIC_URL}/uploads/${item}`}
alt="photo"
/>
</Card>
);
})}
</div>
)}
</div>
</div>
</div>
{formData.deleteVisible && formData.photo !== null ? (
<Modal
visible={formData.deleteVisible}
title="Kasowanie zdjęcia"
onOk={() => {
deletePhoto(formData.photo);
setFormData({ ...formData, deleteVisible: false, photo: null });
}}
onCancel={() =>
setFormData({ ...formData, deleteVisible: false, photo: null })
}
footer={[
<Button
key="back"
onClick={() =>
setFormData({
...formData,
deleteVisible: false,
photo: null
})
}
>
Zamknij
</Button>,
<Button
key="accept"
onClick={() => {
deletePhoto(formData.photo);
setFormData({
...formData,
deleteVisible: false,
photo: null
});
}}
>
Skasuj
</Button>
]}
>
<p>Na pewno chcesz skasować to zdjęcie?</p>
</Modal>
) : (
""
)}
</Fragment>
);
}
};
AdminGallery.propTypes = {
photos: PropTypes.object.isRequired,
getPhotos: PropTypes.func.isRequired,
addGalleryPhoto: PropTypes.func.isRequired,
deletePhoto: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
photos: state.photos
});
export default connect(mapStateToProps, {
addGalleryPhoto,
getPhotos,
deletePhoto
})(AdminGallery);
Ok guys i've found an issue. I have nginx on my droplet and default file size to upload in nginx is set to 1mb. This line in nginx conf will do the job client_max_body_size 100M; Of course 100M is for example.
I want to use image uploader from AntDesign library. Here is a snapshot
import { Upload, Icon, Modal } from 'antd'
class PicturesWall extends React.Component {
state = {
previewVisible: false,
previewImage: '',
fileList: [],
}
handleCancel = () => this.setState({ previewVisible: false })
handlePreview = file => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
})
}
handleChange = ({ fileList }) => this.setState({ fileList })
render() {
const { previewVisible, previewImage, fileList } = this.state
const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">Upload</div>
</div>
)
return (
<div className="clearfix">
<Upload
action="//jsonplaceholder.typicode.com/posts/"
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
>
{fileList.length >= 3 ? null : uploadButton}
</Upload>
<Modal
visible={previewVisible}
footer={null}
onCancel={this.handleCancel}
>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
)
}
}
ReactDOM.render(<PicturesWall />, mountNode)
It's so hard to understand what's going on here for me .
Can I get images from this component using something like
const img=event.target.files[0];?
All I want it's put that uploaded images into array and using FormData send axios.post request to the backend.
I'm newbie in React .If it's something obvious pardon me.Thank you in advance
antd's Upload component is doing the upload for you under the hood. But if you don't want to do that, and upload the file later, you can also achieve that with the help of beforeUpload prop.
From the docs:
beforeUpload: Hook function which will be executed before uploading. Uploading will be stopped with false or a rejected Promise returned. Warning:this function is not supported in IE9
I have written an example and added comments where necessary:
class PicturesWall extends React.Component {
state = {
previewVisible: false,
previewImage: "",
fileList: []
};
handleCancel = () => this.setState({ previewVisible: false });
handlePreview = file => {
this.setState({
previewImage: file.thumbUrl,
previewVisible: true
});
};
handleUpload = ({ fileList }) => {
//---------------^^^^^----------------
// this is equivalent to your "const img = event.target.files[0]"
// here, antd is giving you an array of files, just like event.target.files
// but the structure is a bit different that the original file
// the original file is located at the `originFileObj` key of each of this files
// so `event.target.files[0]` is actually fileList[0].originFileObj
console.log('fileList', fileList);
// you store them in state, so that you can make a http req with them later
this.setState({ fileList });
};
handleSubmit = event => {
event.preventDefault();
let formData = new FormData();
// add one or more of your files in FormData
// again, the original file is located at the `originFileObj` key
formData.append("file", this.state.fileList[0].originFileObj);
axios
.post("http://api.foo.com/bar", formData)
.then(res => {
console.log("res", res);
})
.catch(err => {
console.log("err", err);
});
};
render() {
const { previewVisible, previewImage, fileList } = this.state;
const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">Upload</div>
</div>
);
return (
<div>
<Upload
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleUpload}
beforeUpload={() => false} // return false so that antd doesn't upload the picture right away
>
{uploadButton}
</Upload>
<Button onClick={this.handleSubmit} // this button click will trigger the manual upload
>
Submit
</Button>
<Modal
visible={previewVisible}
footer={null}
onCancel={this.handleCancel}
>
<img alt="example" style={{ width: "100%" }} src={previewImage} />
</Modal>
</div>
);
}
}
ReactDOM.render(<PicturesWall />, document.getElementById("container"));