React fetch - initial state not loading - what can I do? - reactjs

I have started to learn react two days ago, so I am a complete newbie. I am attempting to create a simple website app that loads beer data (image, name, tagline) from a public API on cards. Upon clicking on the card, it should display description, name, tagline.
My problem is that upon initial load, no data loads - each card only loads after I click on it.after clicking one card twice
It was working fine before I introduced the clicking function and backFacingCard.
I tried several things, including making separate components for each card side but like I said, I am still very new to react and coding in general, so I am not sure if what I do is correct. I would be very grateful for any tips and tricks.
Here is my code for the card component:
const BeerTile = (props) => {
const frontFacingCard = {
src: (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const backFacingCard = {
src: (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const [card, setCard] = useState(frontFacingCard.src);
const [showsFront, setShowsFront] = useState(true);
const clickHandler = () => {
if (showsFront) {
setCard(backFacingCard.src);
setShowsFront(false);
props.frontSide(showsFront);
} else {
setCard(frontFacingCard.src);
setShowsFront(true);
props.frontSide(showsFront);
}
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{card}
</div>
);
};

in your second component you can use useEffect
const [card, setCard] = useState(frontFacingCard.src);
const [showsFront, setShowsFront] = useState(true);
useEffect(()=>{
console.log("frontFacingCard.src",frontFacingCard.src)//check if source is available
setCard(frontFacingCard.src)
},[frontFacingCard.src])
const clickHandler = () => {
if (showsFront) {
setCard(backFacingCard.src);
setShowsFront(false);
props.frontSide(showsFront);
} else {
setCard(frontFacingCard.src);
setShowsFront(true);
props.frontSide(showsFront);
}
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{card}
</div>
);
};

you can do this alternate solution
const BeerTile = (props) => {
const FrontFacingCard = () => {
return (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
)
};
const BackFacingCard =()=> {
return (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
)
};
const [showsFront, setShowsFront] = useState(true);
const clickHandler = () => {
setShowsFront(!showFront);
props.frontSide(showsFront);
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{
showsFront
? <FrontFacingCard />
: <BackFacingCard />
}
</div>
);
};

Checkout this cleaner solution, that separate back,front and Tile.
const BeerTile = (props) => {
const [front, setFront] = useState(true);
const clickHandler = () => {
setFront(!front)
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{front?<FrontFacingCard {...props}/>:<BackFacingCard {...props}/> }
</div>
);
};
const FrontFacingCard=(props)=>
(
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const BackFacingCard =( props)=>(
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
);

Related

I can not display data from django rest framework with axios

I am still new.
I am making my portfolio.But I got problem.
I am trying to get data from django rest framework with axios. It says I got no error.
I want to display the data in cards components.
But still it does not show data in the browser.
How can I solve this problem?
Thank you in advance.
//App.tsx
const App: React.FC = () => {
const [loading, setLoading] = useState(false);
const [results, setResults] = useState<EventProps[]>([]);
const url = "http://127.0.0.1:8000/events/lists/";
useEffect(() => {
const getEventsData = async () => {
try {
const res = await axios.get<EventProps[]>(url).then((res) => {
setResults(res.data);
setLoading(true);
// console.log(res.data.results.event_id);
console.log(res);
console.log(res.data);
});
} catch (err) {
console.log(err);
}
};
getEventsData();
}, []);
return (
<>
<div className="wholeheader">
<MantineProvider
inherit
theme={{ defaultGradient: { from: "blue", to: "teal", deg: 20 } }}
>
<Group position="apart" grow>
<Center
sx={(theme) => ({
height: 170,
backgroundImage: theme.fn.gradient(),
color: theme.white,
})}
>
<Logo />
<div className="header">
<HeaderTabsColored {...HeaderProps} />
<LoginAndRegiInHeader />
</div>
<div className="searchbar">
<SearchBar />
</div>
</Center>
</Group>
</MantineProvider>
</div>
{loading ? (
<Fragment>loading..</Fragment>
) : (
Object.values(results).map((result: EventProps) => (
<EventsCard
key={result.event_id}
event_id={result.event_id}
title={result.title}
description={result.description}
dateTime={result.dateTime}
capacity={result.capacity}
EventImage1={result.EventImage1}
EventImage2={result.EventImage2}
EventImage3={result.EventImage3}
location={result.location}
host={result.host}
/>
))
)}
<br />
<br />
<Page />
</>
);
};
export default App;
//Events.tsx
[data in the browser][1]
import { EventProps } from "../types/EventsProps";
import { Grid } from "#mantine/core";
import axios from "axios";
import { ThemeContext } from "#emotion/react";
import eventImage from "../Images/Events/eventImage.jpg";
const useStyles = createStyles((theme) => ({
card: {
backgroundColor:
theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white,
},
section: {
borderBottom: `1px solid ${
theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3]
}`,
paddingLeft: theme.spacing.md,
paddingRight: theme.spacing.md,
paddingBottom: theme.spacing.md,
},
like: {
color: theme.colors.red[6],
},
label: {
textTransform: "uppercase",
fontSize: theme.fontSizes.xs,
fontWeight: 700,
},
}));
// {EventImage1, EventImage2, EventImage3, event_id, location, description, capacity, title, host,dateTime}:
const EventsCard: React.FC<EventProps> = (props) => {
const { classes, theme } = useStyles();
const [opened, setOpened] = useState(false);
return (
<Grid>
<Grid.Col span={4} key={props.event_id}>
<Card withBorder radius="md" p="md" className={classes.card}>
<Card.Section>
<Image
className="image"
src={props.EventImage1}
alt={props.title}
height={300}
width={342}
/>
<Image
className="image"
src={props.EventImage2}
alt={props.title}
height={300}
width={342}
/>
<Image
className="image"
src={props.EventImage3}
alt={props.title}
height={300}
width={342}
/>
</Card.Section>
<Card.Section className={classes.section} mt="md">
<Group position="apart">
<Text size="lg" weight={800}>
{props.title}
<br />
{props.dateTime}
</Text>
<Badge size="sm">{props.location}</Badge>
</Group>
<Text size="lg" weight={500}>
定員:{props.capacity}名
</Text>
<Text size="sm" mt="xs">
{props.description}
</Text>
</Card.Section>
<Card.Section className={classes.section}>
<Text mt="md" className={classes.label} color="dimmed">
host
</Text>
<Text size="sm">{props.host}</Text>
</Card.Section>
</Card>
</Grid.Col>
</Grid>
);
};
export default EventsCard;

How to open component in a new window on button click?

I am new to react.
I am working on a project where I have to show a whiteboard and draw on it.
I want to open the whiteboard when a menu is clicked and on that window I will draw.
How can I do that?
Here is my code:
This is my component for showing menu.
Menu.tsx
export default function Menu(props: { buttonClassName?: string }) {
const [showWindowPortal, setWindowPortal] = useState(false);
const anchorRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
window.addEventListener('beforeunload', () => {
setWindowPortal(false);
});
});
return (
<>
<Button onClick={() => setMenuOpen(isOpen => !isOpen)} ref={anchorRef} className=
{props.buttonClassName}>
{isMobile ? (
<MoreIcon />
) : (
<>
<span style={{ color: '#fff' }}>Settings</span>
<span style={{ color: '#fff', paddingTop: '7px' }}>
<ExpandMoreIcon />
</span>
</>
)}
</Button>
<MenuContainer
open={menuOpen}
onClose={() => setMenuOpen(isOpen => !isOpen)}
anchorEl={anchorRef.current}
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
transformOrigin={{
vertical: isMobile ? -55 : 'bottom',
horizontal: 'center',
}}
>
<MenuItem
onClick={() => {
setWindowPortal(true);
}}
>
<Typography variant="body1">Whiteboard</Typography>
</MenuItem>
</MenuContainer>
{showWindowPortal &&(
<Container
open={showWindowPortal}
onClose={() => {
setSettingsOpen(false);
setMenuOpen(false);
}}
></Container>
)}
</>
);
}
I want to show below component in a new window when I click the menu.
Container.tsx
function Container({ open, onClose }: { open: boolean; onClose: () => void},props:any) {
const classes = useStyles();
const [color, setColor] = useState('#000000');
const [size, setSize] = useState(5);
const [domReady, setDomReady] = useState(false);
let containerEl:any ;
let externalWindow:any ;
useEffect(() => {
externalWindow = window.open('', '', 'width=600,height=400,left=200,top=200');
containerEl = externalWindow.document.createElement('div');
externalWindow.document.body.appendChild(containerEl);
externalWindow.document.title = 'A React portal window';
setDomReady(true);
externalWindow.addEventListener('beforeunload', () => {
//props.closeWindowPortal();
});
return ()=>{
externalWindow.close();
}
});
function changeColor(e: any) {
setColor(e.target.value);
}
function changeSize(e: any) {
setSize(e.target.value);
}
if (!containerEl) {
return null;
}
return domReady? createPortal(<div className="container">Hello</div>
,containerEl):null;
--------I want to show the below to the new window ---------------------
return (
<Dialog open={open} onClose={onClose} classes={{ paper: classes.container }}>
<div className="container">
<div className="tools-section">
<div className="color-picker-container">
Select Brush Color :
<input type="color" value={color} onChange={changeColor} />
</div>
<div className="brushsize-container">
Select Brush Size :
<select value={size} onChange={changeSize}>
<option> 5 </option>
<option> 10 </option>
<option> 15 </option>
<option> 20 </option>
<option> 25 </option>
<option> 30 </option>
</select>
</div>
</div>
<div className="board-container">
<Board color={color} size={size}></Board>
</div>
</div>
</Dialog>
);
}
export default Container;

Why my props are undefined when sending to components?

I have a table in my project and I have an edit / view / add page that I can access from this table. My goal is to send the clicked data to the other component without any problem, but no matter how hard I try, I get an undefined error and the project is broken. I would be glad if you could help.
I am sharing my codes from parent to child component
Table page.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import ManagementTable from '../components/ManagementTable'
import {
getApps,
updateStopRisk,
countLiveCountry,
updateAppShow,
deleteApp,
} from "../api/apiCalls";
import VisibilityIcon from "#material-ui/icons/Visibility";
import DeleteIcon from "#material-ui/icons/Delete";
import EditIcon from "#material-ui/icons/Edit";
import Switch from "#material-ui/core/Switch";
import DeleteModal from "../components/DeleteModal";
import { Link } from "react-router-dom";
const Management = () => {
const [apps, setApps] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [currentApp, setCurrentApp] = useState("");
const [appID, setAppID] = useState(0);
const fetchData = useCallback(async () => {
const { data: appsResponse } = await getApps();
const countLiveCountries = await fetchLiveCountriesForApps(appsResponse);
setApps(
appsResponse.map((app, idx) => ({
...app,
countLiveCountry: countLiveCountries[idx],
}))
);
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const fetchLiveCountriesForApps = async (appwLive) => {
const countLiveCountries = await Promise.all(
appwLive.map((app) => countLiveCountry(app.appID))
);
return countLiveCountries.map(({ data: liveCountries }) => liveCountries);
};
const removeApp = async () => {
await deleteApp(appID);
setModalVisible(false);
fetchData();
};
const onClickCancel = () => {
setModalVisible(false);
};
const columns = useMemo(() => [
{
Header: "Application Name",
accessor: "app_name",
},
{
Header: "Business Area",
accessor: "businessarea.businessarea_name",
},
{
Header: "Live Plants",
accessor: "countLiveCountry",
},
{
Header: "Line Stop Risk",
accessor: "app_stoprisk",
Cell: ({ row: { original } }) => {
const changeCheck = async (id) => {
await updateStopRisk(id);
fetchData();
};
return (
<input
checked={original.app_stoprisk}
onClick={() => {
changeCheck(original.appID);
}}
id="appStopRisk"
type="checkbox"
style={{ width: 18, height: 18, marginTop: 5 }}
/>
)
},
sortType: (a, b, id) => {
if (a.original[id] > b.original[id]) return -1;
if (b.original[id] > a.original[id]) return 1;
},
},
{
Header: "Actions",
Cell: ({ row: { original } }) => {
const changeTrack = async (id) => {
await updateAppShow(id);
fetchData();
};
return (
<>
<Link
className="btn btn-manage-link btn-sm col-2"
to={{
pathname: `/management/${original.app_name}`,
mode: "view",
id: original.appID
}}
>
<VisibilityIcon></VisibilityIcon>
</Link>
<Link
to={{
pathname: `/management/${original.app_name}`,
mode: "edit",
id: original.appID
}}
className="btn btn-manage-link btn-sm col-2"
>
<EditIcon></EditIcon>
</Link>
<button
onClick={() => {
setModalVisible(true);
setCurrentApp(original.app_name);
setAppID(original.appID);
}}
className="btn btn-manage-link btn-sm col-3"
>
<DeleteIcon></DeleteIcon>
</button>
<Switch
onClick={() => changeTrack(original.appID)}
checked={original.app_show}
className="col-3"
></Switch>
</>
)
},
},
],
[fetchData]
);
return (
<div className="container">
<h2 style={{ float: "left", font: "bold" }}>Management</h2>
<div style={{ float: "right" }}>
<Link className="btn btn-danger btn-sm" to={{ pathname: `/management/add`, mode: "add" }}>
Add New App
</Link>
<Link className="btn btn-danger btn-sm ml-3" exact to="/management/plants">
Plant Management
</Link>
</div>
<ManagementTable columns={columns} data={apps} />
<DeleteModal
message={<strong>{currentApp}</strong>}
variety="app"
onClickCancel={onClickCancel}
onClickOk={removeApp}
visible={modalVisible}
/>
</div>
);
};
export default Management;
The page where I transfer the props.
import React, { useState, useEffect } from "react";
import Accordion from "../components/Accordion";
import Details from '../components/Details'
import {
getByIdApps,
} from "../api/apiCalls";
const ApplicationManagement = (props) => {
const [appById, setAppById] = useState([]);
const { id } = props.location;
const [selectOption, setSelectOption] = useState('add')
useEffect(() => {
getData();
getMode();
}, [])
const getData = async () => {
console.log(props.location.id)
if (props.location.id) {
await getByIdApps(props.location.id).then((response) => setAppById(response.data))
console.log(appById)
console.log(props)
}
else {
setSelectOption('add')
}
}
const getMode = () => props.location.mode ? setSelectOption(props.location.mode) : setSelectOption('add')
const handleOptionChange = (event) => {
console.log(event.target.value)
setSelectOption(event.target.value)
}
return (
<>
<div style={{ margin: 20 }}>
<h1>
{appById.app_shortcode} - {appById.app_fullname}
</h1>
<div className="float-right mb-auto">
<label><input type="radio" value="view" checked={selectOption === 'view'} onChange={handleOptionChange} />View</label>
<label> <input type="radio" value="add" checked={selectOption === 'add'} onChange={handleOptionChange} />Add</label>
<label> <input type="radio" value="edit" checked={selectOption === 'edit'} onChange={handleOptionChange} />Edit</label>
</div>
<br></br>
<div style={{ marginLeft: 50, marginRight: 50 }} >
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Links</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Factory Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Issues Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Middleware Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
</div>)
{selectOption === 'add' ? (
<div>
Add Mode
</div>
) : selectOption === 'view' ? (<div>View Mode</div>) : (<div>eidt</div>)}
</div>
</>
);
};
export default ApplicationManagement;
and the section where the details are kept on the ApplicationManagement page (My code is quite long, I just share the problem part.)
import React, { useState, useEffect } from 'react'
import axios from "axios";
import {
getResponsibleTeams,
getBusinessAreas
} from '../api/apiCalls'
const Details = (props) => {
const [rTeams, setrTeams] = useState([]);
const [bAreas, setbAreas] = useState([]);
const { data } = props;
useEffect(() => {
async function fetchData() {
const getrTeams = await getResponsibleTeams();
const getbAreas = await getBusinessAreas();
axios.all([getrTeams, getbAreas]).then(
axios.spread((...allData) => {
const allrTeams = allData[0].data;
const allbAreas = allData[1].data;
setrTeams(allrTeams);
setbAreas(allbAreas);
})
);
}
fetchData();
}, []);
return (
<div>
<div
style={{
float: "left",
width: 1350,
height: 340,
}}
>
<div className="form-group">
<label style={{ float: "left" }} htmlFor="appFullName">
Frontend:{" "}
</label>
<input
id="appFullName"
type="text"
class="form-control"
placeholder="dsfdsdsf"
value={data.frontend.frontend_name} // error here
//onChange={handleInputChange}
name="appShortCode"
style={{ width: 400, marginLeft: 150 }}
/>
</div>
</div>
</div>
)
}
export default Details;
Later I realized that using asynchronous functions caused some problems. I came up with a solution to this and the problem was solved.
Error Code Here :
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
and the solution to the problem
{appById &&
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>}

How can I have multiple dropzones on one page that preview multiple images when using react-dropzone?

I am using react-dropzone on my app and would like to have multiple dropzones on one page to preview multiple images. For example, I would like to be able to drop a hero image onto a dropzone that displays the hero image on the top of the page. I would then like to drop a different image onto a different dropzone that displays the image in a thumbnail container.
import React, { useState, useMemo, useEffect } from "react";
import Container from "../components/Container";
import { useDropzone } from "react-dropzone";
const Test = () => {
// Dropzone
const baseStyle = {
flex: 1,
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "20px",
borderWidth: 2,
borderRadius: 2,
borderColor: "#eeeeee",
borderStyle: "dashed",
backgroundColor: "#fafafa",
color: "#bdbdbd",
outline: "none",
transition: "border .24s ease-in-out",
};
const activeStyle = {
borderColor: "#2196f3",
};
const acceptStyle = {
borderColor: "#00e676",
};
const rejectStyle = {
borderColor: "#ff1744",
};
const [files, setFiles] = useState({});
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
accept: "image/*",
onDrop: (acceptedFiles) => {
console.log(acceptedFiles);
setFiles(
Object.assign(acceptedFiles[0], {
preview: URL.createObjectURL(acceptedFiles[0]),
})
);
},
});
const style = useMemo(
() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {}),
}),
[isDragActive, isDragReject, isDragAccept]
);
useEffect(
() => () => {
// Make sure to revoke the data uris to avoid memory leaks
URL.revokeObjectURL(files.preview);
},
[files]
);
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<div>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be the dropzone for the Thumbnail image */}
<div>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be where the Hero image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Hero Image"
/>
{/* This would be where the Thumbnail image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Thumbnail Image"
/>
</Container>
);
};
export default Test;
I'm guessing I need to modify the onDrop function but I can't figure how to do this. Any help would be greatly appreciated!
Create two separate file variables and handle them separately.
use two separate getRootsProps and getInputProps on both inputs.
const [file, setFile] = useState({});
const [fileGallery, setFileGallery] = useState({});
const { getRootProps:getRootfileProps, getInputProps:getInputfileProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFile(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFileGallery(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<div>
<div {...getRootfileProps({ style })}>
<input {...getInputfileProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be the dropzone for the Thumbnail image */}
<div>
<div {...getRootGalleryProps({ style })}>
<input {...getInputGalleryProps()} />
<span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
</div>
</div>
{/* This would be where the Hero image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Hero Image"
/>
{/* This would be where the Thumbnail image is displayed */}
<img
style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
alt="Thumbnail Image"
/>
</Container>
);
};
export default Test;
you need to create two separate file variables and handle them separately. also you are using same getRootsProps and getInputProps on both inputs which is not correct.
const [file, setFile] = useState({});
const [fileGallery, setFileGallery] = useState({});
const { getRootProps:getRootfileProps, getInputProps:getInputfileProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFile(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
accept: 'image/*',
onDrop: (acceptedFile) => {
setFileGallery(
Object.assign(acceptedFile[0], {
preview: URL.createObjectURL(acceptedFile[0]),
}),
);
},
});
You should use two separate filenames on the state one for hero one for thumbnail and manage each of them for each dropzones
something like this:
const [heroFiles, setHeroFiles] = useState({});
const [filesThumb, setFilesThumb] = useState({});
you are using the Dropzone hook and that will make it difficult to achieve what you are intending to, use the Dropzone component instead and declare state for each Dropzone input you intend to use.
import React, { useState } from "react";
import Container from "../components/Container";
import Dropzone from "react-dropzone";
const Test = () => {
const [heroFiles, setHeroFiles] = useState([]);
const [thumbnailFiles, setThumbnailFiles] = useState([]);
return (
<Container>
{/* This would be the dropzone for the Hero image */}
<Dropzone onDrop={(acceptedFiles) => {
setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}} name="heroImage" multiple={false}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>
Drop hero image here, or click to select file
</span>
</div>
)}
</Dropzone>
{/* This would be the dropzone for the Thumbnail image */}
<Dropzone onDrop={(acceptedFiles) => {
setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}} name="heroImage" multiple={false}>
{({getRootProps, getInputProps}) => (
<div {...getRootProps({className: 'dropzone'})}>
<input {...getInputProps()} />
<span style={{ fontSize: ".8rem" }}>
Drop hero image here, or click to select file
</span>
</div>
)}
</Dropzone>
{/* This would be where the Hero image is displayed */}
<img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={heroFiles.length > 0 ? heroFiles[0].preview : "https://via.placeholder.com/600x200"} alt="Hero Image"/>
{/* This would be where the Thumbnail image is displayed */}
<img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={thumbnailFiles.length > 0 ? thumbnailFiles[0].preview : "https://via.placeholder.com/600x200"} alt="Thumbnail Image"/>
</Container>
);
}
export default Test;
this is supposed to take care of your issues.

Is there any difference between using React.lazy suspense against using onLoad prop in a <img>?

I would like to know which are the benefits of using React Lazy and Supense against what I am showing you below. First Example is using useState and Onload Prop, and second example is using React Lazy and Suspense.
const ImageComponent = ({ src }) => {
const [load, setLoad] = useState(false);
//handles load of the image
const handleOnload = () => {
setLoad(true);
};
return (
<>
{!load && <Spinner>}
<img
src={src}
alt="Avatar"
onLoad={handleOnload}
style={{
height: '192px',
width: '50%',
display: load ? 'inline' : 'none',
}}
/>
</>
);
};
VS this
<Suspense
fallback={
<Spinner style={{ width: '50%' }} />
}
>
<ImageComponent src={listItem.download_url} />
</Suspense>
ImageComponent.js
const ImageComponent = ({ src }) => {
return (
<img
src={src}
alt="Avatar"
style={{
height: '192px',
width: '50%',
}}
/>
);
};
export default ImageComponent;

Resources