Drag and drop images in React - javascript

I'm trying to implement drag and drop behaviour using React JS and react-dropzone library with showing thumbnails.
The code is as follows:
import React from "react";
import ReactDOM from "react-dom";
import Dropzone from "react-dropzone";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
dropzone1: [],
dropzone2: []
};
}
addFilesToDropzone(files, dropzone) {
let files_with_preview = [];
files.map(file => {
file["preview"] = URL.createObjectURL(file);
files_with_preview.push(file);
});
const new_files = [...this.state[dropzone], ...files_with_preview];
this.setState({ [dropzone]: new_files });
}
render() {
return (
<div className="App">
<Dropzone
onDrop={files => {
this.addFilesToDropzone(files, "dropzone1");
}}
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()} className="">
<input {...getInputProps()} />
<div style={{ height: 100, backgroundColor: "yellow" }}>
Drop some files here
{dropzone1.map(file => (
<img
src={file.preview}
alt={file.path}
style={{ width: 40, height: 40 }}
/>
))}
</div>
</div>
)}
</Dropzone>
<div style={{ display: "flex", flexDirection: "row", marginTop: 25 }}>
<div style={{ width: "100%" }}>
DROPZONE 2
<Dropzone
onDrop={files => {
this.addFilesToDropzone(files, "dropzone2");
}}
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()} className="">
<input {...getInputProps()} />
<div style={{ height: 100, backgroundColor: "yellow" }}>
Drop some files here
{this.state.dropzone2.map(file => (
<img
src={file.preview}
alt="dsds"
style={{ width: 40, height: 40 }}
/>
))}
</div>
</div>
)}
</Dropzone>
</div>
</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Here is the example on codesandbox.
Everything works fine when I drag files from a folder on my computer, but I want to be able to drag thumbnails generated with dropzone 1 to a dropzone 2. But that doesn't work.
Any idea how to do that?

Yes, that doesn't work because that's not what react-dropzone is designed for. Quote from the website,
Simple React hook to create a HTML5-compliant drag'n'drop zone for files.
Use react-dnd or react-beautiful-dnd instead.

You can use another package: react-file-drop

Related

React is only passing the last object in my array to a component

I have a react component where I map through a list of clients and display each client in a card.
return (
<div className='VolunteerClientsTab'>
{volunteerClients && volunteerClients.map((client) => (
<React.Fragment key={client.id}>
<div className='VolunteerClientsTab__card'>
<Avatar style={{ alignSelf: 'center', marginTop: '.5rem' }}>{client.first_name[0]}{client.last_name[0]}</Avatar>
<h2>{client.first_name} {client.last_name}</h2>
<h4>Details</h4>
<p><AiOutlineMail style={iconStyles} /> {client.email}</p>
<p><AiOutlinePhone style={iconStyles} /> {formatPhoneNumber(client.contact_number)}</p>
<h4 style={{ marginTop: '1rem' }}>Actions</h4>
<p onClick={handleOpenClientNeedsModal} className='hover-underline'><BiDonateHeart style={iconStyles} />View Needs</p>
<p className='hover-underline'><HiOutlineDocumentReport style={iconStyles} />Write Report</p>
<p className='hover-underline'><FiVideo style={iconStyles} />Contact Client</p>
</div>
<ClientNeeds open={openClientNeedsModal} handleClose={handleCloseClientNeedsModal} client={client} />
</React.Fragment>
))}
</div>
)
};
ClientNeeds is a component that renders an MUI modal to display additional client information. I am passing it the client object within the loop but when I open the modal only the client of the last index in the volunteerClients array was passed to all the modal components. Does anyone have any idea why this is happening?
ClientNeeds component
import React from 'react';
import Box from '#mui/material/Box';
import Modal from '#mui/material/Modal';
import PropTypes from 'prop-types';
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 400,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const ClientNeeds = ({ open, handleClose, client }) => {
return (
<div>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={style}>
<h2>{client.email}</h2>
</Box>
</Modal>
</div>
)
};
ClientNeeds.propTypes = {
open: PropTypes.bool,
handleClose: PropTypes.func,
client: PropTypes.object
};
export default ClientNeeds;
MY SOLUTION
Passing the client onClick to an additional global state object and passing that state object to the modal,
const [selectedClient, setSelectedClient] = useState(null)
also only rendering the clientNeedsModal is there is an object in that state.
<div className='VolunteerClientsTab'>
{volunteerClients && volunteerClients.map((client) => (
<React.Fragment key={client.id}>
<div className='VolunteerClientsTab__card'>
<Avatar style={{ alignSelf: 'center', marginTop: '.5rem' }}>{client.first_name[0]}{client.last_name[0]}</Avatar>
<h2>{client.first_name} {client.last_name}</h2>
<h4>Details</h4>
<p><AiOutlineMail style={iconStyles} /> {client.email}</p>
<p><AiOutlinePhone style={iconStyles} /> {formatPhoneNumber(client.contact_number)}</p>
<h4 style={{ marginTop: '1rem' }}>Actions</h4>
<p onClick={() => handleOpenNeeds(client)} className='hover-underline'><BiDonateHeart style={iconStyles} />View Needs</p>
<p className='hover-underline'><HiOutlineDocumentReport style={iconStyles} />Write Report</p>
<p className='hover-underline'><FiVideo style={iconStyles} />Schedule Meeting</p>
</div>
{selectedClient ? (
<ClientNeeds open={openClientNeedsModal} handleClose={handleCloseClientNeedsModal} client={selectedClient} />
) : null}
</React.Fragment>
))}
</div>
const handleCloseClientNeedsModal = () => {
setSelectedClient(null)
setOpenClientNeedsModal(false);
}
const handleOpenNeeds = (client) => {
setSelectedClient(client)
handleOpenClientNeedsModal()
}
This allows me to pass any individual object within my array to the modal component as originally desired

React-slick - how to change custom arrow colour based on the page number

There are 2 custom arrows which are previous-arrow and next-arrow
There are also total 3 pages with 3 slides per page
What I want to do is whenever the page is the first page/last page, the previous arrow/next arrow will apply filter in svg, which means the previous arrow/next arrow will become black color
<img
…
filter:
"invert(3%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
}}
/>
For example, if it’s the first page, the previous arrow will be filtered while next arrow will NOT be filtered.
Is it possible to do it?
App.js
import "./styles.css";
import React from "react";
import Slider from "react-slick";
import ArrowPrevious from "./arrow-previous.svg";
import ArrowNext from "./arrow-next.svg";
const ArrowButton = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
"invert(3%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
}}
/>
</button>
);
};
export default function App() {
const settings = {
dots: true,
infinite: false,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3,
prevArrow: <ArrowButton imgSrc={ArrowPrevious} imgAlt="previous-button" />,
nextArrow: <ArrowButton imgSrc={ArrowNext} imgAlt="next-button" />,
beforeChange: (current, next) => {
console.log(next);
}
};
return (
<div>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
</Slider>
</div>
);
}
Codesandbox
https://codesandbox.io/s/focused-dubinsky-9onwe?file=/src/App.js
See codesandbox
https://codesandbox.io/s/inspiring-austin-k9i86?file=/src/App.js:510-527
You just have to look for the onClick !== null
I broke your arrows into 2 separate components though i.e. ArrowButtonNext and ArrowButtonPrevious
const ArrowButtonPrevious = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
onClick === null
? "invert(93%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
: "none"
}}
/>
</button>
);
};
const ArrowButtonNext = ({ imgSrc, imgAlt, onClick }) => {
return (
<button
onClick={onClick}
style={{ backgroundColor: "transparent", border: "none" }}
>
<img
src={imgSrc}
alt={imgAlt}
style={{
width: "50px",
height: "50px",
filter:
onClick === null
? "invert(93%) sepia(7%) saturate(7029%) hue-rotate(94deg) brightness(86%) contrast(93%)"
: "none"
}}
/>
</button>
);
};
I have Checked on Code sandbox and inspect the arrow ,you can change only background Color or else you need to import arrow icon from Material UI or Bootstrap

Why doesn't my image show on my react app page?

So i've been trying to show an image on my page with an API, but everytime I go to the page I see the image for a few seconds and after that the page refreshes and it shows an error:
Uncaught TypeError: location is undefined
I think the problem could be about the way I used my image, but i am not sure. If I console log the image it just shows the correct image name. This is the code I used:
import { Row, Col } from "react-grid-system";
import { Separator } from "#fluentui/react";
import * as React from "react";
import { useEffect, useState } from "react";
function Recipe(props) {
const axios = require('axios');
const api = axios.create({
baseURL: 'http://localhost:5000/',
timeout: 10000
})
const [recipe, setRecipe] = useState({});
const [image, setImage] = useState({});
useEffect(() => {
getRecipe()
}, [])
function getRecipe() {
api.get('/recipe/' + props.id).then(res => {
setRecipe(res.data);
setImage("https://localhost:5001/Uploads/" + res.data.image)
});
}
return (
<div>
<div>
<Row>
<Col sm={6} md={6} lg={6}>
<img style={{ width: "700px", marginTop: "20px" }} src={image} alt={"error"} />
</Col>
<Col style={{ marginTop: "20px" }} sm={6} md={6} lg={6}>
<Separator className={"Separator"} />
<h1>Naam: <div style={{ fontSize: "20px" }}>{recipe.name}</div></h1>
<h1>Ingredienten: <div style={{ fontSize: "20px" }}> {recipe.ingredients}</div>
</h1>
<h1>Macro's:
<div style={{ fontSize: "20px" }}>
<ul>
<li>Kcal: {recipe.carbs}</li>
</ul>
</div>
</h1>
<h1>Voorbereiding: <div style={{ fontSize: "12px" }}>
{recipe.preparation} </div></h1>
</Col>
</Row>
</div>
</div>
)
}
export default Recipe

Unable to set zIndex fro autocomplete in reactjs

I am working on a project where i have to implement a search bar which should be in my header component , when ever i try to search the search is working fine but at the same time the search options are overlapping the my content below it. how can i resolve this?
I tried adding zIndex both using css and noraml jsx way both dint work for me bellow is my code.
Header.js
import React, { Component } from 'react';
import Autocomplete from 'react-autocomplete';
import { getStocks, matchStocks } from './data';
class Header extends Component {
state = { value: '' };
render() {
return (
<div style={{ marginTop: 0, marginLeft: 0 }}>
<div className="callout primary" id="Header">
<div className="row column">
<h1>{this.props.name}</h1>
<div style={{ zIndex: 10 }}> // this is where i am trying to set the zIndex
<Autocomplete
classNames={{ autocompleteContainer: 'ac-container' }}
value={ this.state.value }
inputProps={{ id: 'states-autocomplete' }}
wrapperStyle={{ position: 'relative', display: 'inline-block' }}
items={ getStocks() }
getItemValue={ item => item.name }
shouldItemRender={ matchStocks }
onChange={(event, value) => this.setState({ value }) }
onSelect={ value => this.setState({ value }) }
renderMenu={ children => (
<div className = "menu">
{ children }
</div>
)}
renderItem={ (item, isHighlighted) => (
<div
className={`item ${isHighlighted ? 'item-highlighted' : ''}`}
key={ item.abbr } >
{ item.name }
</div>
)}
/>
</div>
</div>
</div>
</div>
);
}
}
export default Header;

react-carousel-slider doesn't rerender

guys! Have a problem with rerendering of slider component. After choosing another SELECT option, other images are to be loaded to carousel component. But!! Nothing happens! Props of component are being changed, and developer tools show slides (images) are changed, but nothing happens on DOM.
Below i post code. What do you think? Where is the problem?
import React from 'react';
import CarouselSlider from "react-carousel-slider";
import { FormControl } from 'react-bootstrap';
class StampChoose extends React.Component {
changeSamplesType = (e) => {
const sampleType = e.target.value;
this.props.changeSamplesType(sampleType);
this.forceUpdate();
}
render() {
let btnWrapperStyle = {
position: "relative",
borderRadius: "50%",
height: "50px",
width: "50px",
textAlign: "center"
}
let btnStyle = {
display: "inline-block",
position: "relative",
top: "90%",
transform: "translateY(-50%)",
fontSize: "36px"
}
let rBtnCpnt = (<div style = {btnWrapperStyle} >
<div style = {btnStyle} className = "material-icons" >
<i className="fas fa-angle-right"></i>
</div>
</div>);
let lBtnCpnt = (<div style = {btnWrapperStyle} >
<div style = {btnStyle} className = "material-icons" >
<i className="fas fa-angle-left"></i>
</div>
</div>);
let iconItemsStyle = {
padding: "0px",
background: "transparent",
margin:"0 5px",
height: "80%"
};
const titles = this.props.titles;
const slides = this.props.slides;
return (
<React.Fragment>
<FormControl componentClass="select" onChange={ this.changeSamplesType }>
<option value="type1">{ titles['type1'] }</option>
<option value="type2">{ titles['type2'] }</option>
<option value="type3">{ titles['type3'] }</option>
<option value="type4">{ titles['type4'] }</option>
</FormControl>
<CarouselSlider
sliderBoxStyle = {{height: "150px", width: "90%", background: "transparent", overflow: "hidden"}}
accEle = {{dots: false}}
newState={ this.state }
slideCpnts = {slides}
itemsStyle = {iconItemsStyle}
buttonSetting = {{placeOn: 'middle-outside'}}
rBtnCpnt = {rBtnCpnt}
lBtnCpnt = {lBtnCpnt}
/>
</React.Fragment>
)
}
}
export default StampChoose;
import React from 'react';
import { Grid, Row, Col, ControlLabel } from 'react-bootstrap';
import { samples, titles} from '../../../samples-stamps';
import StampChoose from './StampChoose';
const Sample = (props) => (
<React.Fragment>
{
<div>
<img src={ `images/samples/${props.img}` } alt={ props.title } />
</div>
}
</React.Fragment>
);
class StampsSamples extends React.Component {
state = {
sampleType: 'type1'
}
changeSamplesType = (sampleType) => {
this.setState({ sampleType });
}
render() {
const sampleType = this.state.sampleType;
let slides = Object.keys(samples[sampleType]).map((item, i) => {
return (
<div>
<Sample
key={i}
title={ samples[sampleType][item].title }
img={ samples[sampleType][item].img }
productId={ samples[sampleType][item].id }
/>
</div>
);
});
return (
<Grid>
<Row>
<Col md={ 4 }>
<ControlLabel>Примерный образец оттиска <br/>
<small>(выберите образец оттиска)</small>
</ControlLabel>
</Col>
<Col md={ 8 }>
<StampChoose
slides={ slides }
titles={ titles }
changeSamplesType={ this.changeSamplesType }
/>
</Col>
</Row>
</Grid>
);
}
}
export default StampsSamples;
In your Sample Component your returning an object inside of React.Fragment. Does it have anything to do with that? What if you remove the { and } inside there and try? Like below. Don't know if thats the issue but try. You also have an extra DIV in your map method for the slides. If you check the instructions for the React Carousel Slider they dont use these extra DIVs and {}
<React.Fragment>
<div>
<img src={ `images/samples/${props.img}` } alt={ props.title } />
</div>
</React.Fragment>

Categories