I am running into an issue where regardless of what component is clicked in a list of Job items, it returns the id of the last element only.
I have a key passed to the mapped list:
let activeListings = jobs.filter((job) => !job.isArchived);
activeListings?.map((job) => {
return (
<div key={job._id} className="bg-white w-8/12 py-4 my-4">
<Job
job={job}
setJob={setJobs}
handleShowDetailsToggle={handleShowDetailsToggle}
archiveToggler={archiveToggler}
setShowingResumeModal={setShowingResumeModal}
setShowingCoverLetterModal={setShowingCoverLetterModal}
showingResumeModal={showingResumeModal}
showingCoverLetterModal={showingCoverLetterModal}
getJobs={getJobs}
key={job._id}
/>
</div>
);
})
In the Job component, there is a button that when clicked opens a modal to select a file to upload and a preview.
Regardless of which Job component the Upload component is called from, it always gets passed the job._id from the final Job component listed.
Here is the resume modal component that opens on the button click:
import React, { useState } from "react";
import Upload from "../../Upload";
const AddNewResumeModal = (props) => {
const { setShowingResumeModal, job, getJobs, id } = props;
const [previewSource, setPreviewSource] = useState("");
return (
<div className="resume-modal-background">
<div className="resume-modal-container">
<button
className="close-modal-btn"
onClick={() => setShowingResumeModal(false)}
>
×
</button>
<h1 className="resume-modal-title">Upload Resume</h1>
<button onClick={() => console.log(job._id)}>Test2</button>
<Upload
resume={true}
setShowingResumeModal={setShowingResumeModal}
job={job}
getJobs={getJobs}
previewSource={previewSource}
setPreviewSource={setPreviewSource}
/>
<div></div>
</div>
</div>
);
};
export default AddNewResumeModal;
and the Upload component it renders:
import React, { useState } from "react";
import { Viewer } from "#react-pdf-viewer/core";
import "#react-pdf-viewer/core/lib/styles/index.css";
const URL = "http://localhost:8000";
const Upload = (props) => {
const {
setShowingResumeModal,
job,
getJobs,
previewSource,
setPreviewSource,
} = props;
const [fileInputState, setFileInputState] = useState("");
// const [previewSource, setPreviewSource] = useState("");
const handleFileInputChange = (e) => {
const file = e.target.files[0];
console.log(file);
previewFile(file);
};
const previewFile = (file) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setPreviewSource(reader.result);
};
};
const handleSubmitFile = (e) => {
e.preventDefault();
if (!previewSource) return;
uploadFile(previewSource, job._id);
getJobs();
setShowingResumeModal(false);
};
const uploadFile = async (base64encodedFile, id) => {
console.log(base64encodedFile);
console.log(id);
try {
await fetch(`${URL}/upload/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ data: base64encodedFile }),
});
} catch (error) {
console.error(error);
}
};
return (
<div>
<form>
<input
type="file"
name="pdf"
id="pdf"
accept=".pdf"
onChange={handleFileInputChange}
value={fileInputState}
className="form-input"
onClick={() => console.log(job._id)}
/>
</form>
<div className="preview-container">
{previewSource ? (
<div className="viewer-container">
<Viewer fileUrl={previewSource} />
</div>
) : (
<div className="no-preview-source">Preview area</div>
)}
</div>
<button
onClick={handleSubmitFile}
type="submit"
className="upload-submit-btn"
>
Upload Resume
</button>
</div>
);
};
export default Upload;
Please help me understand how to correctly pair each job listing so that the correct id of the job is passed to the backend.
Related
I am a beginner in react js programming. I'm trying to do the todo project, which is a classic project. When I delete or add an element from the list, the newly formed list appears on the screen by combining with the previous one, I will show it with a picture below. I did not understand the source of the eror so wanted to post it here to get some advices suggestions about why it is happening.Thank you.(I am getting and storing data in firebase firestore database)
Before Adding an element initial array state
After adding an element to the array.
I am using useState for array and using useEffect to get initial data
MainPage.js that contains form and the list components.
const MainPage = () => {
const [isLoading, setLoding] = useState(true);
const [array, setArray] = useState([]);
const sub = async (email) => {
var result = [];
await onSnapshot(doc(db, "users", email), (doc) => {
var data = doc.data().todos;
data.forEach((element) => {
Object.keys(element).map(() => {
result.push(element["title"]);
});
});
setArray(result);
setLoding(false);
});
};
useEffect(() => {
sub(auth.currentUser.email);
}, []);
const onAddToDo = (todoTitle) => {
setArray((prevAray) => {
return [...prevAray, todoTitle];
});
};
const onRemove = (title) => {
setArray((prevAray) => {
return [array.pop(array.indexOf(title))];
});
};
return (
<div>
{isLoading && <h1>Loading</h1>}
{!isLoading && (
<div>
<section>
<NavBar></NavBar>
<ToDoForm passData={onAddToDo} />
</section>
<section>
<CardList removeCards={onRemove} array={array} />
</section>
</div>
)}
</div>
);
};
export default MainPage;
Firebase.js that stores the firebase update methods
export const deleteItem = (title) => {
updateDoc(doc(db, "users", auth.currentUser.email), {
todos: arrayRemove({ title: title }),
});
};
export const addnewTodo = (title) => {
updateDoc(doc(db, "users", auth.currentUser.email), {
todos: arrayUnion({ title: title }),
});
};
TodoForm.js component
const ToDoForm = (props) => {
const [todoTitle, setTitle] = useState("");
const titleChangeHandler = (event) => {
setTitle(event.target.value);
};
const newTodoAdder = (event) => {
event.preventDefault();
addnewTodo(todoTitle);
props.passData(todoTitle);
};
return (
<div className="form_holder">
<div className="form_container">
<form onSubmit={newTodoAdder}>
<h3>Add Events</h3>
<label>Title</label>
<input
onChange={titleChangeHandler}
type="text"
placeholder="Title"
id="title"
></input>
<div className="holder">
<button type="sumbit">Add</button>
</div>
</form>
</div>
</div>
);
};
export default ToDoForm;
CardList.js component
const CardList = (props) => {
const array = props.array;
if (array.length === 0) {
return (
<div className="grid_container">
<h2>Found no todos</h2>
</div>
);
}
return (
<div className="grid_container">
{array.map((element, index) => {
return (
<Card
removeSelf={() => {
props.removeCards(element);
}}
key={index}
title={element}
/>
);
})}
</div>
);
};
export default CardList;
Card.js component
const Card = (props) => {
const handleRemove = (event) => {
event.preventDefault();
deleteItem(props.title);
props.removeSelf();
};
return (
<div className="card">
<h2 className="card__title">{props.title}</h2>
<button type="button" onClick={handleRemove}>
Delete
</button>
</div>
);
};
export default Card;
EDIT ;
Index.js file
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
SOLUTION
I fixed the issue by changing the add and remove functions that were inside of MainPage.js file You can see the new versions bellow. Hope someday it will help somebody.
Use effect was called once all I had to do get the data again after a change...
New Remove and Add functions
const onAddToDo = (todoTitle) => {
console.log(todoTitle + " Added");
sub(auth.currentUser.email);
};
const onRemove = (title) => {
console.log(title + " Deleted");
sub(auth.currentUser.email);
};
I am creating a page to update product details on an e-commerce site I am building using NextJS, and I have the image upload section nested inside an accordion on the individual item page. Once images have been uploaded, I would like to clear the upload form and close the accordion. It is closing the accordion I am having trouble with.
ImageUploadAccordion.js:
import React, {useRef} from 'react';
import {Accordion} from 'react-bootstrap'
import ImageUpload from './ImageUpload'
export default function ImageUploadAccordion({ item }) {
const accordionRef = useRef(null);
const toggleAccordion = () => {
accordionRef.current.click();
}
return (
<Accordion ref={accordionRef} defaultActiveKey="0">
<Accordion.Item eventKey="1">
<Accordion.Header>
<span className="btn btn-outline-success">Upload Images</span>
</Accordion.Header>
<Accordion.Body>
<ImageUpload
toggle={toggleAccordion}
item={item}
/>
</Accordion.Body>
</Accordion.Item>
</Accordion>
)
}
ImageUpload.js:
import React, {useState} from 'react';
import { useRouter } from 'next/router'
export default function ImageUpload({ item, toggle }) {
const router = useRouter()
const [images, setImages] = useState([])
const [imageURLS, setImageURLS] = useState([])
const [tags, setTags] = useState([])
const [theInputKey, setTheInputKey] = useState('')
const uploadImageToClient = (event) => {
if (event.target.files && event.target.files[0]) {
setImages((imageList) => [...imageList, {"index": images.length, "data": event.target.files[0]}]);
setImageURLS((urlList) => [
...urlList,
URL.createObjectURL(event.target.files[0])
]);
}
let randomString = Math.random().toString(36);
setTheInputKey(randomString)
};
const uploadTagToClient = (e) => {
if (event.target.value) {
const name = e.target.getAttribute("name")
// const i = event.target.value;
// document.getElementById("image-upload")
setTags((tagList) => [...tagList, {"name": name, "tag": e.target.value}]);
}
};
const removeImage = (name) => {
// debug
alert(`Trying to remove image index ${name}`)
let newImages = []
let newTags = []
setImages(images.filter(image => image.data.name !== name));
setTags(tags.filter(tag => tag.name !== name));
}
const uploadToServer = async (e) => {
const body = new FormData()
images.map((file, index) => {
body.append(`file${index}`, file.data);
});
// Use the filenames as keys then we can retrieve server side once we have the images
tags.map((tag, index) => {
body.append(tag.name, tag.tag)
})
const response = await fetch("/api/file", {
method: "POST",
"Content-Type": "multipart/form-data",
body
})
var message = await response.json();
alert(message['message'])
setImages([])
setTags([])
toggle()
};
const openImageUploadDialogue = () =>{
document.getElementById("image-upload").click()
}
return (
<div className="container">
<input style={{display:'none'}} accept="image/*" id="image-upload" type="file" key={theInputKey || '' } className="btn btn-outline-success-inverse" onChange={uploadImageToClient} />
<button className="btn btn-outline-success-inverse" onClick={openImageUploadDialogue} >
Add Image
</button>
<hr className = "text-pink"/>
<div className="row">
<div className="col d-flex flex-wrap">
{images.map((file, index) => {
return (
<div className="div p-1" key={file.data.name}>
<p className="text-pink">{file.data.name}</p>
<p>Tag</p>
<input type="text" name={file.data.name} id={`${file.data.name}`} onChange={uploadTagToClient} />
<img src={imageURLS[index]} height="200" width="150" />
<div className="btn btn-outline-success-inverse" onClick={ () =>removeImage(file.data.name)}>Remove Image</div>
</div>
);
})}
</div>
<button
className="btn btn-outline-success-inverse"
type="submit"
onClick={uploadToServer}
>
Upload Images
</button>
</div>
</div>
);
}
I tried by creating a reference to the accordion using useRef, and a function which uses this reference to activate the click event, which I passed to the ImageUpload component, according to another answer to a similar question, but it doesn't seem to work and I'm unsure as to why.
Any help always appreciated :-)
I believe you have the wrong target as the ref, update it to target the button that is automatically generated to wrap the header content.
<h2 class="accordion-header"><button type="button" aria-expanded="true" class="accordion-button"><span class="btn btn-outline-success">Upload Images</span></button></h2>
Rudimentary example:
export default function ImageUploadAccordion({ item }) {
const accordionRef = useRef(null);
const toggleAccordion = () => {
accordionRef.current.querySelector('button').click();
}
return (
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="1">
<Accordion.Header ref={accordionRef}>
<span className="btn btn-outline-success">Upload Images</span>
</Accordion.Header>
<Accordion.Body>
<ImageUpload
toggle={toggleAccordion}
item={item}
/>
</Accordion.Body>
</Accordion.Item>
</Accordion>
)
}
I'm using REACTJS and the very well known material framework:
https://www.creative-tim.com/learning-lab/nextjs/core-upload/material-dashboard#example-1
I import the component:
import ImageUpload from 'components/CustomUpload/ImageUpload.js';
I put the code into the render function from the parent class:
<ImageUpload avatar/>
But how to get the file URL back and to transform the file in base64?
Thank you ;-)
This is the code of the child class:
import React from "react";
// used for making the prop types of this component
import PropTypes from "prop-types";
// core components
import Button from "components/CustomButtons/Button.js";
import defaultImage from "assets/img/image_placeholder.jpg";
import defaultAvatar from "assets/img/placeholder.jpg";
export default function ImageUpload(props) {
const [file, setFile] = React.useState(null);
const [imagePreviewUrl, setImagePreviewUrl] = React.useState(
props.avatar ? defaultAvatar : defaultImage
);
let fileInput = React.createRef();
const handleImageChange = e => {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
setFile(file);
setImagePreviewUrl(reader.result);
};
if (file) {
reader.readAsDataURL(file);
}
};
// eslint-disable-next-line
const handleSubmit = e => {
e.preventDefault();
// file is the file/image uploaded
// in this function you can save the image (file) on form submit
// you have to call it yourself
};
const handleClick = () => {
fileInput.current.click();
};
const handleRemove = () => {
setFile(null);
setImagePreviewUrl(props.avatar ? defaultAvatar : defaultImage);
fileInput.current.value = null;
};
let { avatar, addButtonProps, changeButtonProps, removeButtonProps } = props;
return (
<div className="fileinput text-center">
<input type="file" onChange={handleImageChange} ref={fileInput} />
<div className={"thumbnail" + (avatar ? " img-circle" : "")}>
<img src={imagePreviewUrl} alt="..." />
</div>
<div>
{file === null ? (
<Button {...addButtonProps} onClick={() => handleClick()}>
{avatar ? "Add Photo" : "Select image"}
</Button>
) : (
<span>
<Button {...changeButtonProps} onClick={() => handleClick()}>
Change
</Button>
{avatar ? <br /> : null}
<Button {...removeButtonProps} onClick={() => handleRemove()}>
<i className="fas fa-times" /> Remove
</Button>
</span>
)}
</div>
</div>
);
}
ImageUpload.propTypes = {
avatar: PropTypes.bool,
addButtonProps: PropTypes.object,
changeButtonProps: PropTypes.object,
removeButtonProps: PropTypes.object
};
I got this component in React.js which make different kinds of filtering when I click a button, this is my code:
import React, { useContext } from 'react';
import { ModelsContext } from "../context/ModelsContext";
const FilterNav = () => {
const { modelos, guardarModelo } = useContext(ModelsContext);
const filterSegment = e => {
const segment = modelos.filter(modelo => modelo.segment === e.target.name);
guardarModelo(segment);
}
return (
<nav className="filter-container">
<div className="container">
<h3 className="filter-element-title">Filtrar por</h3>
<button type="button" className="filter-element">Todos</button>
<button type="button" className="filter-element" name="Autos" onClick={filterSegment}>Autos</button>
<button type="button" className="filter-element" name="Pickups y Comerciales" onClick={filterSegment}>Pickups y Comerciales</button>
<button type="button" className="filter-element" name="SUVs y Crossovers" onClick={filterSegment}>SUVs y Crossovers</button>
</div>
<p className="filter-element-last">Ordenar por ^</p>
</nav>
);
}
export default FilterNav;
The information I get from the api with useContext in ModelsContext.jsx, here is what I wrote so far:
import React, { createContext, useState, useEffect } from 'react';
export const ModelsContext = createContext();
const ModelsProvider = (props) => {
//State de modelos
const [modelos, guardarModelo] = useState([]);
const consultarAPI = async () => {
const api = await fetch("https://challenge.agenciaego.tech/models");
const modelos = await api.json();
guardarModelo(modelos);
}
//Cargar un modelo
useEffect(() => {
consultarAPI()
}, []);
return (
<ModelsContext.Provider
value={{
modelos,
guardarModelo
}}
>
{props.children}
</ModelsContext.Provider>
)
}
export default ModelsProvider;
My issue is that when I filter the API modelos throught the filterSegment function I don't know how to re-fetch the data from the API, because when I do a new call to the filterSegment function it filters the filtered data. I've tried to add a boolean state, and I was thinking about adding another state with allthedata, but I really lost about implementing it, I'm still very new to React.js.
I've search through stack overflow and google and I cannot get the answer, If you can give me a clue or some sort of guidance it will be appreciated.
Thanks so much!
You can add another state in the ModelsContext:
//State de modelos
const [modelos, guardarModelo] = useState([]);
const [allModelos, guardarAllModelo] = useState([]);
const consultarAPI = async () => {
const api = await fetch("https://challenge.agenciaego.tech/models");
const modelos = await api.json();
guardarAllModelo(modelos);
//uncomment if you want to have initial value for modelos state
//guardarModelo(modelos);
}
// some codes ...
<ModelsContext.Provider
value={{
allModelos,
modelos,
guardarModelo
}}
>
{props.children}
</ModelsContext.Provider>
Then in the FilterNav component:
const {allModelos, modelos, guardarModelo } = useContext(ModelsContext);
const filterSegment = e => {
const segment = allModelos.filter(modelo => modelo.segment === e.target.name);
guardarModelo(segment);
}
But this does not really re-fetch data from your web api. It just re-filters the first fetched data. if you want to re-fetch data from web api you can add consultarAPI in your context provider then call it somewhere.
Thanks code is working
This is my Portfolio gallery code First time load all data when click category then get category dataenter code here
Thanks code is working
This is my Portfolio gallery code First time load all data when click category then get category data`enter code here`
import React, { Component, useEffect, useState } from 'react'`enter code here`;
import Thumnailport_list from './Thumnailport_list';
import Portlightbox from './Portlightbox';
import Functional from './Functional';
import $ from 'jquery';
const Portfolio = () => {
const filterItem = async (categoryitem) => {
const updateitmes = allModelos.filter((curElm) => {
return curElm.categories === categoryitem
})
getporfolioState(updateitmes)
}
const [getporfolio, getporfolioState] = useState([])
const [allModelos, guardarAllModelo] = useState([]);
$(document).ready(function () {
$(".grid-wrap .grid li").unbind().click(function (e) {
console.log(this.className);
var newe = this.className;
$('.' + newe).addClass('current show');
$("#grid-gallery").addClass("slideshow-open");
});
$("#closeport").unbind().click(function (e) {
$("#grid-gallery").removeClass("slideshow-open");
$(".portfolio .grid li").removeClass('current show');
$(".portfolio .slideshow ul > li").removeClass('current show');
});
});
const portadd = () => {
document.body.classList.add('portfolio');
document.body.classList.add('at-top');
document.getElementById('port').classList.add('no-transform');
document.getElementById('port').classList.add('revealator-within');
document.getElementById('port2').classList.add('no-transform');
document.getElementById('port2').classList.add('revealator-within');
document.getElementById('navbar-collapse-toggle').classList.remove('biohidemenu');
}
const getalldata = async () => {
try {
const res = await fetch("/getdata", {
method: 'Get',
headers: {
'Content-Type': 'application/json'
}
})
const data = await res.json()
// console.log("This is our data load")
// console.log(data.portfolio)
getporfolioState(data.portfolio)
guardarAllModelo(data.portfolio)
} catch (error) {
console.log(error)
// history.push("/backoffice/login")
}
}
useEffect(() => {
getalldata()
portadd()
}, []);
return (
<>
<section id="port" class="title-section text-left text-sm-center revealator-slideup revealator-once revealator-delay1">
<h1 >my <span>portfolio</span></h1>
<span class="title-bg">works</span>
</section>
<section id="port2" className="main-content text-center revealator-slideup revealator-once revealator-delay1">
<div class="container">
<button className="btn btn-about " onClick={() => filterItem('mobileapp')}>Mobile</button>
<button className="btn btn-about " onClick={() => filterItem('frontend')}>Frontend</button>
<button className="btn btn-about " onClick={() => filterItem('gdesign')}>Graphics</button>
</div>
<div id="grid-gallery" className="container grid-gallery">
{/* Portfolio Grid Starts */}
<section className="grid-wrap">
<ul className="row grid">
{
getporfolio.map((getdata, index) => {
return (
<>
<Thumnailport_list
key={index}
portID={getdata._id}
imagetag={getdata.imguploadedFile}
figuertext={getdata.projectname}
/>
</>
)
})
}
</ul>
</section>
{/* Portfolio Grid Ends */}
{/* Portfolio Details Starts */}
<section className="slideshow" id="sdfer">
<ul>
{/* Portfolio Item Detail Starts */}
{
getporfolio.map((getdata, index) => {
return (
<>
<Portlightbox
idlight={getdata._id}
imagelight={getdata.imguploadedFile}
langport={getdata.language}
clientport={getdata.client}
projectnameport={getdata.projectname}
previewport={getdata.preview}
/>
</>
)
})
}
</ul>
{/* Portfolio Navigation Starts */}
<nav>
{/*<span className="icon nav-prev prev"><img src="images/left-arrow.png" alt="previous" /></span>
<span className="icon nav-next next"><img src="images/right-arrow.png" alt="next" /></span>*/}
<span className="nav-close" id="closeport"><img src="images/close-button.png" alt="close" /> </span>
</nav>
{/* Portfolio Navigation Ends */}
</section>
</div>
</section>
</>
)
}
export default Portfolio;
I'm trying to make a file uploader in ReactJS. I managed to get it all done, except for the part that I show the image to the user. I'm able to make the name show up, but the image does not appear.
I think it's going to be easier if I show the code, so, here it goes
FileUploader Component
import React, { useState } from 'react';
import axios from 'axios'
function FileUploader() {
const [file, setFile] = useState('')
const [fileName, setFileName] = useState('Choose File')
const [selectedFile, setSelectedFile] = useState({
filePath: '',
fileName: ''
})
const handleChange = e => {
setFile(e.target.files[0])
setFileName(e.target.files[0].name)
}
const handleUpload = async e => {
e.preventDefault()
const data = new FormData()
data.append('file', file)
const res = await axios.post('http://localhost:8000/upload', data)
const { path, originalname } = res.data
setSelectedFile({filePath: path, fileName: originalname})
}
return (
<>
<div className="custom-file mb-4">
<input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
<label className="custom-file-label" htmlFor="customFile">{fileName}</label>
</div>
<button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>
{selectedFile.filePath !== '' ? (
<div className='row mt-5'>
<div className='col-md-6 m-auto'>
<h3 className='text-center'>{selectedFile.fileName}</h3>
<img style={{ width: '100%' }} src={selectedFile.filePath} alt='' />
</div>
</div>
) : null}
</>
);
}
export default FileUploader;
I think you should use blob image by using URL.createObjectUrl
Below is updated code
import React, { useState } from 'react';
import axios from 'axios'
function FileUploader() {
const [file, setFile] = useState('')
const [fileName, setFileName] = useState('Choose File')
const [selectedFile, setSelectedFile] = useState({
filePath: '',
fileName: ''
})
const [blobImage, setBlobImage] = useState() // <= add
const handleChange = e => {
setFile(e.target.files[0])
setFileName(e.target.files[0].name)
setBlobImage(URL.createObjectURL(e.target.files[0])) // <= add
}
const handleUpload = async e => {
e.preventDefault()
const data = new FormData()
data.append('file', file)
const res = await axios.post('http://localhost:8000/upload', data)
const { path, originalname } = res.data
setSelectedFile({filePath: path, fileName: originalname})
}
return (
<>
<div className="custom-file mb-4">
<input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
<label className="custom-file-label" htmlFor="customFile">{fileName}</label>
</div>
<button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>
{selectedFile.filePath !== '' ? (
<div className='row mt-5'>
<div className='col-md-6 m-auto'>
<h3 className='text-center'>{selectedFile.fileName}</h3>
<img style={{ width: '100%' }} src={blobImage} alt='' /> // <= change src to blobImage
</div>
</div>
) : null}
</>
);
}
export default FileUploader;
I wrote an article about file uploading with React and DnD but it's not that far off from what you're trying to accomplish:
Build A React Drag & Drop Progress File Uploader
My guess is that you're wanting to display the file preview of the image that is about to be uploaded. You can do this by loading the image into the local state, although you'll have to be careful if it's a large image as it can crash the browser.
Click the "Run code snippet" to see it in action.
// main.js
const { useState } = React;
const App = () => {
// State / Props
const [preview, setPreview] = useState(null);
// Functions
const onInputFileChange = event => {
// reset each time
setPreview(null);
// Define supported mime types
const supportedFilesTypes = ['image/jpeg', 'image/png'];
if (event.target.files.length > 0) {
// Get the type of the first indexed file
const { type } = event.target.files[0];
if (supportedFilesTypes.indexOf(type) > -1) {
const reader = new FileReader();
reader.onload = e => { setPreview(e.target.result); };
reader.readAsDataURL(event.target.files[0]);
}
}
};
return (<div><h1>Choose an image</h1><input onChange={onInputFileChange} type="file" name="file" />{preview && <img src={preview} />}</div>);
};
ReactDOM.render(<App />, document.getElementById('root'));
<body>
<div id="root"></div>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script type="text/babel" src="main.js"></script>
</body>