How to create react js drag and drop file upload simply? - javascript

I want to create react js drag and drop file upload using class component !!
I have tried the normal file upload and it works fine, in addition I have tried using the react-drag-drop library, I can't access the file properties !!

react-dropzone uses React hooks to create HTML5-compliant React components for handling the dragging and dropping of files. react-dropzone provides the added functionality of restricting file types and also customizing the dropzone.
To install
npm install --save react-dropzone
Example of drag-and-drop component
import React, {useEffect, useState} from 'react';
import {useDropzone} from 'react-dropzone';
function App(props) {
const [files, setFiles] = useState([]);
const {getRootProps, getInputProps} = useDropzone({
accept: 'image/*',
onDrop: acceptedFiles => {
setFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}
});
const thumbs = files.map(file => (
<div style={thumb} key={file.name}>
<div style={thumbInner}>
<img
src={file.preview}
style={img}
/>
</div>
</div>
));
useEffect(() => {
// Make sure to revoke the data uris to avoid memory leaks
files.forEach(file => URL.revokeObjectURL(file.preview));
}, [files]);
return (
<section className="container">
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
<aside style={thumbsContainer}>
{thumbs}
</aside>
</section>
);
}
export default App

Related

File explorer filtering in react js

I am new to react. A task assigned to create drag and drop component. I followed some blogs to do the task, which only accept image file types. Now the task is when clicked on the upload icon it should open file explorer which should only show image type files. I cannot try to figure out how that would work. Part of my codes which i took from various blogs are:
Drag and drop component:
import React from "react";
import { useDropzone } from "react-dropzone";
import UploadIcon from '#mui/icons-material/Upload';
const Dropzone = ({ onDrop, accept }) => {
// Initializing useDropzone hooks with options
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept
});
/*
useDropzone hooks exposes two functions called getRootProps and getInputProps
and also exposes isDragActive boolean
*/
return (
<div className="dropzone-div" {...getRootProps()}>
<input className="dropzone-input" {...getInputProps()} accept=".gif,.jpg,.jpeg,.png"/>
<div className="text-center">
<UploadIcon fontSize="large"/>
{isDragActive ? (
<p className="dropzone-content"> Release to drop the files here</p>
) : (
<p className="dropzone-content">
<b> Choose a file </b> or drag it here
</p>
)}
</div>
</div>
);
};
export default Dropzone;
In the app.js
import React, { useCallback,useState } from "react";
import './App.css';
import Form from './components/Form';
import DragDrop from './components/DragDrop';
import ImageList from "./components/ImageList";
import cuid from "cuid";
function App() {
const [images, setImages] = useState([]);
const [errorMessage, setErrorMessage] = useState([]);
const onDrop = useCallback(acceptedFiles => {
// Loop through accepted files
acceptedFiles.map(file => {
// Initialize FileReader browser API
if (!file.name.match(/\.(jpg|jpeg|PNG|gif|JPEG|png|JPG|gif)$/)) {
setErrorMessage('please select valid file image');
//this.setState({ invalidImage: 'Please select valid image.' });
return false;
}
if(file.name.match(/\.(jpg|jpeg|PNG|gif|JPEG|png|JPG|gif)$/)){
const reader = new FileReader();
// onload callback gets called after the reader reads the file data
reader.onload = function(e) {
// add the image into the state. Since FileReader reading process is asynchronous, its better to get the latest snapshot state (i.e., prevState) and update it.
setImages(prevState => [
...prevState,
{ id: cuid(), src: e.target.result }
]);
setErrorMessage();
};
// Read the file as Data URL (since we accept only images)
reader.readAsDataURL(file);
}
return file;
});
}, []);
return (
<main className="App">
<h2 className="App">Drag and Drop Example</h2>
<br />
<div className=".dropzone-div">
<DragDrop onDrop={onDrop} accept={ 'image/*'}/>
</div>
<div className="App">
{errorMessage && <span> {errorMessage} </span>}
<ImageList images={images} />
</div>
</main>
);
}
export default App;
Use an input element with the type as file, like so:
<span>
<label for="upload">Upload</label>
<input id="upload" type="file" accept="image/*" />
</span>
You could of course change the label to your liking, such as an upload icon.
This is a native HTML element that comes with the functionality you want, out of the box. It is tempting to code everything by hand, especially if you're a beginner. Just remember to search for native solutions before you try a new functionality, or even better, familiarize yourself with the docs of the language/framework you're using.
By the way, here's the MDN doc for the file input element: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

useEffect fetch not retrieving data from local db.json

Im trying to mock a Plant API by using a db.json file (relative path: src\plant-api\db.json), and passing it from the parent component (ItemList) to its child (Item) but its not working because i see no data displayed on screen even tho i can see it in my console.log.
Heres the full code
import React, { useState, useEffect } from "react";
import Item from "./Item";
import Data from "../plant-api/db.json"
const ItemList = () => {
const [plants, setPlants] = useState([]);
useEffect(() => {
fetch(Data)
.then((response) => response.json())
.then((data) => setPlants(data));
}, []);
console.log(Data)
return (
<div className="items">
{plants.map((plant) => {
return (
<div>
<Item data={plant} />
</div>
);
})}
</div>
);
};
export default ItemList;
import React from "react";
import ItemCount from "./ItemCount";
const Item = ({ data }) => {
return (
<div>
<div className="item">
<img src={data.pic} alt="plant-image" />
<h3>{data.name}</h3>
<p>{data.category}</p>
<h4>{data.price}</h4>
<ItemCount stock="10" initial="0" />
</div>
</div>
);
};
export default Item;
directory structure
Any help is needed and appreciated!
maybe you can use the json-server package, so you can create a dummy API,.
an example of using code like the one below in the terminal, make sure the code is run in the db.json file directory.
npx json-server db.json -p2000
later there will be a json server running as an API on port 2000
fetch is used to make network calls, but since you have already have Data imported, you can just set the data in your useEffect hook: setPlants(Data); This should be enough if you're just trying to see how the data renders.
If your data is already in JSON format, you don't need to use a fetch, you can just pop it straight into the const [plants, setPlants] = useState(Data).
If you're trying to simulate a live API, you will have to create a dummy API as Dedi mentioned.

How should I traverse through a folder of .gifs to display them in a list using Gatsby.js

I am trying to figure out how to best display a list of gifs, for starters, located locally in a directory on my machine using Gatsby.js. I did a long Gatsby tutorial that went through using gatbsy-remark and gatsby-image-remark, etc and found that those plugins did not like .gifs... Specifically, anything that required the gatsby plugin 'gatsby-plugin-sharp' and 'gatsby-transformer-sharp' did not work when trying to display gifs. GrahpQL even warns you that targeting childImageSharp on an object that is a .gif will return null and it does...
So I have this gatsby code I'm using in a navigation component...
import React from "react"
import Logo from "../images/glitch-logo.gif"
import Menu from "./menu"
import * as headerStyles from './header.module.scss'
class Navigation extends React.Component {
render() {
return (
<>
<img className={headerStyles.logo} src={Logo} alt="NFT Category Filter" onClick={() => this.toggleMenu()} onKeyDown={this.handleClick}></img>
<Menu ref={el => (this.childMenu = el)} />
</>
)
}
toggleMenu() {
this.childMenu.open()
}
}
export default Navigation
can't I just do something similar in my index file if, for example, I wanted to display an array of .gifs? Something like this?
import * as ImageList from '../images/categories' //folder with .gifs!!!
import Layout from '../components/layout'
import * as layoutStyles from '../components/layout.module.scss'
const IndexPage = () => {
const ImageList = (props) => {
const nfts = props.nfts;
const listImages = nfts.map((nft) => {
<li>{nft}</li>
}
)
}
or is there a plugin for gatsby worth downloading that makes using .gifs easier?
Your approach, assuming all the notation-related stuff (paths, naming, etc) is correct. However, your IndexPage should look like:
const IndexPage = (props) => {
const nfts = props.nfts;
return <ul>
{nfts.map((nft) => {
return <li>{nft}</li>
}}
</ul>
}
.map loops need to return an array, you were missing the statement.
The props are inherited from the top-level components, not from their inner functions. So props, should be got by IndexPage and used in the JSX loop in the return statement of the component.

using rich-markdown-editor react

I am trying to use rich-markdown-editor to get values but the method am using is not modular. Can someone suggest a better way. I have tried both onChange and onSave but cannot seem to get them to work.According to their documentation
onSave({ done: boolean }): void
This callback is triggered when the user explicitly requests to save using a keyboard shortcut, Cmd+S or Cmd+Enter. You can use this as a signal to save the document to a remote server.
onChange(() => value): void
This callback is triggered when the contents of the editor changes, usually due to user input such as a keystroke or using formatting options. You may use this to locally persist the editors state.
import React, { useState } from "react";
import Editor from "rich-markdown-editor";
const Whiteboard = () => {
const [content, setContent] = useState("");
return (
<div>
<div>
<h1>Your Content</h1>
<Editor id="123" value={content} onChange={setContent} />
</div>
{content}
</div>
);
};
export default Whiteboard;
Try
<Editor id="123" value={content} onChange={(value) => setContent(value()} />

Fetch data at component level and have it prerendered/ssr nextjs

I'm working with Nextjs for the first time.
I'm trying to create multiple layouts which will consist on a <Header><different-layouts-for-each><Footer> structure.
The issue that I'm facing is that getStaticProps or getServerProps can run at the page level only.
Since I need SEO on the navigation I suppose I should get it's props on every single page file using one of the two mentioned methods.
The problem here is that I'd have to get the menu props on each one of the pages, but having different templates I will have to repeat myself on all of them in order to bring the content statically or prerendered and be SEO readable.
Getting the menu props on the <MainNav> component would be the ideal situation.
I tried doing an asnyc/await on the component:
<Header> component
import Logo from "../components/header/logo";
import MainNav from "../components/header/mainnav.js";
function Header() {
return (
<div className="headwrapper container mx-auto py-8 flex items-center">
<Logo />
<MainNav/>
</div>
);
}
export default Header;
<MainNav> component
import Link from "next/link";
import { WpHeader } from "../../lib/wpapi";
import React, { useEffect, useState } from "react";
function MainNav() {
const [nav, setNav] = useState(0);
useEffect(() => {
const fetchData = async () => {
const wp = new WpHeader();
const call = await wp.getAxiosMenu();
console.log(call);
setNav(call);
};
fetchData();
}, []);
return (
<div className="navigation text-right w-3/4">
<ul className="main-navigation">
{nav
? nav.map(item => (
<li key={item.id} className="inline-block mx-2">
<Link href={item.path}>
<a>{item.label}</a>
</Link>
</li>
))
: "loading"}
</ul>
</div>
);
}
export default MainNav;
The issue here is that this will return a promise and the html will show "loading" instead of the actual menu html.
Any help or article that could help me on this?
Thanks.

Categories