In the project I have a Upload image component that asks the user for an image and then previews it on the page. The image is not persay "uploaded" to any server and I hope that it does'nt need to. The goal is to be able to compare this uploded image with a random active set of images from an API (Image.js). What I have problem with is how to use the previewImage: URL.createObjectURL(event.target.files[0]) inside of another file, or at least that is what I belive to be the right way to think about it. (For context: The idea is to check the correlation between the uploaded file and the random active set.)
I have tried to implement an child to child state transfer but gave up when it did not work for the child to parent part. App.js is the parent, Image.js and image-upload.component.js are the children. I have also looked for ways to solve this with redux but don't understand how to store images or utilize states inside of the store. For this i only need to update the image state when files are selected by user.
To somewhat summarize and clarify the question: How can I transfer the chosen image file between two components and use the data in both of them?
This is my first project in React so the code may be caotic and full of "brute force" so I apologice in advance for that. Any help or guidence is greatly appreciated!
App.js:
import React from "react";
import "./App.css";
import Navbar from './components/Navbar/Navbar'
import "bootstrap/dist/css/bootstrap.min.css";
import UploadImages from "./components/image-upload.component";
import Images from "./components/Images";
function App() {
return (
<div className="App">
<Navbar />
<div className="container">
<div className="row">
<div className="col-5">
<div className="content">
<h3>Title</h3>
<h4>Upload my picture here</h4>
<UploadImages/>
</div>
</div>
<div className="col-2">
</div>
<div className="col-5">
<Images />
</div>
</div>
</div>
</div>
);
}
export default App;
Images.js (pure, brute force code i guess):
import UploadImages from "./image-upload.component";
import React, {useEffect, useState} from "react";
import "./Images.css";
function shuffleArray(array) {
let i = array.length - 1;
for (; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function Images() {
const [urls, setURLs] = useState([]);
const [count, setCount] =useState(0)
useEffect(() => {
const urls = [
250940,
20622,
436625,
436444,
436509,
359245,
459090,
333933,
333916,
466350,
44831,
383010,
202660,
406317,
337349,
503448,
12617,
248662,
435805,
438545
].map(
(itemId) =>
`https://collectionapi.metmuseum.org/public/collection/v1/objects/${itemId}`
);
shuffleArray(urls)
Promise.all(
urls.map((currUrl) =>
fetch(currUrl)
.then((response) => response.json())
.then((data) => data.primaryImage)
.catch((error) => console.log("There was a problem!", error))
)
).then((fetchedUrls) => setURLs(fetchedUrls));
}, []);
if (count === 3) {
return (
<div>
<div class="imageContainer">
<div class="images__item">
<img class="photo" src={urls[1]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[2]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[3]} alt="" />
</div>
</div>
<button
onClick={() => setCount(4)}>
Next
</button>
</div>
)
}
if (count === 4) {
return (
<div>
<div class="imageContainer">
<div class="images__item">
<img class="photo" src={urls[1]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[2]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[3]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[4]} alt="" />
</div>
</div>
<button
onClick={() => setCount(3)}>
Previous
</button>
<button
onClick={() => setCount(5)}>
Next
</button>
</div>
)
}
if (count === 5) {
return (
<div>
<div class="imageContainer">
<div class="images__item">
<img class="photo" src={urls[1]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[2]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[3]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[4]} alt="" />
</div>
<div class="images__item">
<img class="photo" src={urls[5]} alt="" />
</div>
</div>
<button
onClick={() => setCount(4)}>
Previous
</button>
<button
onClick={() => {setCount(3); shuffleArray(urls);}}>
Reset
</button>
</div>
)
}
else {
return (
<div>
{/* <UploadImages upsideEmit={getStateFromChild} /> */}
<button
onClick={() => {shuffleArray(urls); setCount(3);}}>
Open
</button>
</div>
);
}
}
export default Images;
image-upload.component.js:
import React, { Component } from "react";
import UploadService from "../services/file-upload.service";
import "./Images"
class UploadImages extends Component {
constructor(props) {
super(props);
this.selectFile = this.selectFile.bind(this);
this.upload = this.upload.bind(this);
this.state = {
currentFile: undefined,
previewImage: undefined,
progress: 0,
message: "",
imageInfos: [],
};
}
componentDidMount() {
UploadService.getFiles().then((response) => {
this.setState({
imageInfos: response.data,
});
});
}
selectFile(event) {
this.setState({
currentFile: event.target.files[0],
previewImage: URL.createObjectURL(event.target.files[0]),
message: ""
});
}
upload() {
this.setState({
progress: 0,
});
UploadService.upload(this.state.currentFile, (files) => {
this.setState({
imageInfos: files.data,
});
})
}
render() {
const {
previewImage,
} = this.state;
return (
<div>
<div className="row">
<div className="col-8">
<label className="btn btn-default p-0">
<input type="file" accept="image/*" onChange={this.selectFile} />
</label>
</div>
<div className="col-4">
</div>
</div>
{previewImage && (
<div>
<img className="preview" src={previewImage} alt="" />
</div>
)}
</div>
);
}
}
export default UploadImages
In general you would want to useContext hook for this.
Check out this tutorial https://dev.to/email2vimalraj/react-hooks-lift-up--pass-down-state-using-usecontext-and-usereducer-5ai0
Related
i'm creating a blog. in my index.js i have a left sidebar that shows the article links.
What I'm trying to do is when I click on the link the post content should be shown in the right sidebar of my index.js
At the moment it's been opened in a new page.
index.js
const IndexPage = ({
data: {
allMarkdownRemark: { edges },
},
}) => {
const PostData = edges[0]
const Posts = edges
.filter(edge => !!edge.node.frontmatter.date) // You can filter your posts based on some criteria
.map(edge => <PostLink key={edge.node.id} post={edge.node} />)
return (
<div className='html-container'>
<div className='main-container'>
<div className='row'>
<div className='left-sidebar'>
<div className='logo'>
<p>logo</p>
</div>
<div className='menu'>
{Posts}
</div>
<div className='social'>
<img src={twitch} />
<img src={discord} />
<img src={twitter} />
<img src={email} />
</div>
</div>
<div className='right-sidebar'>
</div>
</div>
</div>
</div>
)
}
post-link.js
import React from "react"
import { Link } from "gatsby"
const PostLink = ({ post }) => (
<div>
<Link to={"/blog"+post.frontmatter.slug}>
{post.frontmatter.title}
{/* {post.frontmatter.title} ({post.frontmatter.date}) */}
</Link>
</div>
)
export default PostLink
Check the API of the Link and if it has an equivalent of target attribute.
I am trying to make a popUp for each of my gallery items containing some information on the picture. Clicking on the picture and showing the pop up works fine, but I can't close it. I get the error that can be read in the title. I understand that there probably is an error regarding the sending of the "setButtonPopUp", but I couldn't understand it yet.
PopUp.js
import React from "react";
import "./PopUp.css";
export default function PopUp(props) {
return props.trigger ? (
<div className="popUpWrapper">
<div className="popUp">
<button
className="closePopUp"
onClick={onClick={props.setTrigger}}
>
close
</button>
{props.children}
</div>
</div>
) : (
""
);
}
GalleryItem.js
import "./GalleryItem.css";
import TextItem from "../TextItem/TextItem.js";
import AlertMessage from "../alertMessage.js";
import PopUp from "../PopUp/PopUp.js";
import { useState } from "react";
export default function GalleryItem({ itemData }) {
const [buttonPopUp, setButtonPopUp] = useState(false);
if (itemData.polaroid === "light") {
return (
<div
className="itemContainer"
onClick={() => setButtonPopUp(true)}
>
<PopUp trigger={buttonPopUp} setTrigger={() => {
setButtonPopUp(false);
}}>
<h3>Info</h3>
<p>{itemData.info}</p>
</PopUp>
<img className="clip" src="../../assets/klammer.png" alt="" />
<img className="polaroid" src="../../assets/polaroid.png" alt="" />
<img className="image" src={itemData.src} alt="" />
<h2 className="polaroidTitleLight">{itemData.title}</h2>
</div>
);
} else if (itemData.polaroid === "dark") {
return (
<div
className="itemContainer"
onClick={() => AlertMessage(itemData.info)}
>
<img className="clip" src="../../assets/klammer.png" alt="" />
<img className="polaroid" src="../../assets/polaroid_dark.png" alt="" />
<img className="image" src={itemData.src} alt="" />
<h2 className="polaroidTitleDark">{itemData.title}</h2>
</div>
);
} else {
return <TextItem itemData={itemData} />;
}
}
What I did notice is that if I try to use the PopUp Component directly in App.js, the PopUp works just fine. But If I try to use it in SiteChanger it's not working anymore. This is the App.js:
App.js
import "./App.css";
import Header from "../Header/Header.js";
import SiteChanger from "../changeSite/changeSite.js";
function App() {
return (
<div>
<Header />
<SiteChanger />
</div>
);
}
export default App;
All help would be greatly appreciated!
You're not sending the prop setTrigger here:
<div
className="itemContainer"
onClick={() => setButtonPopUp(true)}
setTrigger={setButtonPopUp} // Should go to down PopUp
>
<PopUp trigger={buttonPopUp}>
<h3>Info</h3>
<p>{itemData.info}</p>
</PopUp>
Also, there's no this in functional components. It's just props. Here's the solution:
<button
className="closePopUp"
onClick={() => props.setTrigger(false)}
//---------------^^^^^ // Update this
>
Send the props to correct component and not <div>:
<div
className="itemContainer"
onClick={() => setButtonPopUp(true)}
// setTrigger={setButtonPopUp} // Remove this and...
>
<PopUp trigger={buttonPopUp} setTrigger={setButtonPopUp}> // Add here.
<h3>Info</h3>
<p>{itemData.info}</p>
</PopUp>
I'm trying to send with props some icons between two components. I import the urls and I'm using it to do the prop object.
This is my main file.
import { useState } from 'react';
import SapIcon from '../images/logo_sap.png';
import ExcelIcon from '../images/logo_excel.png';
import OutlookIcon from '../images/logo_outlook.png';
import BrowserIcon from '../images/logo_webbrowser.png';
import OneDriveIcon from '../images/logo_onedrive.png';
import XhisIcon from '../images/logo_xhis.png';
import LeftBlock from './LeftBlock';
const BotsGrid = () => {
const [icons, setIcons] = useState([{
SapIcon: { SapIcon },
ExcelIcon: { ExcelIcon },
OutlookIcon: { OutlookIcon },
BrowserIcon: { BrowserIcon },
OneDriveIcon: { OneDriveIcon },
XhisIcon: { XhisIcon }
}]);
console.log(icons.SapIcon);
return (
<div className='BotsGrid'>
<div class="site-section bg-light">
<div class="container">
<LeftBlock icons={icons} />
</div>
</div>
</div>
);
}
export default BotsGrid;
I try to import this prop on my LeftBlock.js file but this doesn't work
const LeftBlock = (props) => {
const icons = props.icons;
return (
<div className="LeftBlock">
<div class="row">
<div class="col-lg-6">
<div class="d-flex tutorial-item mb-4">
<div class="container">
<h3>Test</h3>
<img src={ icons.SapIcon } alt="Image" width="12%" height="12%" class='mr-4'/>
<img src={ icons.ExcelIcon } alt="Image" width="8%" height="8%" class='mr-4' />
<img src={ icons.OutlookIcon } alt="Image" width="8%" height="8%" class='mr-4' />
</p>
<p class="meta">
<span class="mr-2 mb-2">Business</span>
</p>
<p>Details</p>
</div>
</div>
I need some help because the page doesn't show the icons.
you are using an array just remove it
const BotsGrid = () => {
const [icons, setIcons] = useState({
SapIcon: SapIcon ,
ExcelIcon: ExcelIcon,
OutlookIcon: OutlookIcon ,
BrowserIcon: BrowserIcon,
OneDriveIcon: OneDriveIcon,
XhisIcon: XhisIcon
});
I wanna dynamically render the images and then show the modal when the image is clicked and it should close when the modal background is clicked. Please help I'm new to React.
What should I do to make it work like is anything wrong in this. I'm stuck in this.
Whenever the images load from the api and I I click on them nothing happens.
import React from "react";
import axios from "axios";
import { Modal } from "./Modal";
class MediaGallery extends React.Component {
constructor() {
super();
this.state = {
data: "",
show: false,
loading: true
};
}
showModal = () => {
this.setState({ show: true });
};
hideModal = () => {
this.setState({ show: false });
};
componentDidMount() {
const url =
"https://amyapi.com";
axios
.get(url)
.then(response => {
this.setState({
data: response.data,
loading: false
});
})
.catch(error => {
console.log(error);
});
}
render() {
let content;
if (this.state.loading) {
content = (
<div>
<div className="modal is-active">
<div className="modal-background has-background-primary" />
<div className="modal-content has-text-centered">
<p classname="image is-48x48">
<img
src="https://raw.githubusercontent.com/sharadcodes/css_snippets/master/Infinity-1.4s-200px.gif?token=AIXQ22JWJBKUHGP45ANQZ4K5SW46A"
alt=""
/>
</p>
</div>
</div>
</div>
);
} else {
content = this.state.data.map((response, index) => {
return (
<div
key={index}
className="column is-one-quarter-desktop is-half-tablet"
style={{ cursor: "zoom-in" }}
onClick={this.showModal}
>
<Modal show={this.state.show} handleClose={this.hideModal}>
<img src={response.acf.image} alt={response.acf.title} />
</Modal>
<div className="card cardimages">
<div className="card-image" id="small-image-zoomable">
<figure className="image is-3by2">
<img src={response.acf.image} alt={response.acf.title} />
</figure>
<div
className="card-content is-overlay is-clipped"
data={response.acf.title}
>
<span className="tag is-primary">{response.acf.title}</span>
</div>
</div>
</div>
</div>
);
});
}
return (
<div>
<section className="hero is-medium is-bold has-background-black has-text-centered">
<div className="hero-body">
<div className="container">
<h1 className="title is-1" style={{ color: "#FFD581" }}>
Captured Moments
</h1>
</div>
</div>
</section>
<div className="section" style={{ marginTop: "-1.2rem" }}>
<div className="container">
<div className="columns is-multiline" id="media-gallery">
{content}
</div>
</div>
</div>
</div>
);
}
}
export default MediaGallery;
And modal code is
import React from "react";
export const Modal = ({ handleClose, show, children }) => {
const showHideClassName = show ? "is-active" : "";
return (
<div>
<div className={{ showHideClassName } + " modal"} id="modal">
<div className="modal-background" onClick={handleClose} />
<div className="modal-content" style={{ width: "70vw!important" }}>
<p className="image ">{children}</p>
</div>
<button
className="modal-close is-large"
aria-label="close"
onClick={handleClose}
/>
</div>
</div>
);
};
I have react js code of inner most child component like this
import React from 'react'
import { addToCart } from 'actions/cart'
export default (props) => {
const { line_item, cart} = props
// const oClick = line_item.oClick.bind(line_item)
const handleClick = (id) => this.props.dispatch(addToCart(id, 1))
// *I am getting error above line*
return (
<div>
<ul className="ul-reset">
<li>
<div className="cart-prod-wrapper cf">
<div className="cart-image-wrapper">
<div className="cart-image">
<a href="#"><img src="#" alt="Product One"/>
</a>
</div>
</div>
<div className="cart-details">
<div className="cart-name">
{line_item.variant.name}
</div>
<div className="cart-price">{line_item.variant.price}</div>
</div>
<div className="cart-qty">
<div className="cart-qty-name">QTY:</div>
<div className="cart-qty-value">
<div class="minus"><span>-</span></div>
{line_item.quantity}
<div class="plus">
<span value = { line_item.variant.id } onClick={handleClick(line_item.variant.id)} >+</span></div>
</div>
</div>
<div className="cart-total">
<div className="cart-total-name">Total</div>
<div className="cart-total-value">{line_item.variant.price * line_item.quantity}</div>
</div>
</div>
</li>
</ul>
</div>
)
}
i want to perform to call an action using dispatch
and code of parent presentation component is line
export default (props) => {
const { account, cart, readMore1} = props
return (
<li>
{ !cart.isFetching && cart.line_items.map(
(line_item, i) => <CartPreview key = {i} line_item= {line_item} cart ={cart} />)
}
</li>
)
}
can any on please guide me to solve this error
Edit
const mapStateToProps = (state) => {
return {
account: getAccount(state),
cart: getCart(state),
classToSend: getReadmore(state),
authenticityToken: getAuthenticityToken(state)
}
}
export default connect(mapStateToProps)(HeaderContainer)
May be this could help
import React from 'react'
import { connect } from 'react-redux' // import connect from redux
import { addToCart } from 'actions/cart'
// name component to wrap it with connect
const MyComponent = (props) => {
const { line_item, cart} = props
return (
<div>
<ul className="ul-reset">
<li>
<div className="cart-prod-wrapper cf">
<div className="cart-image-wrapper">
<div className="cart-image">
<a href="#"><img src="#" alt="Product One"/>
</a>
</div>
</div>
<div className="cart-details">
<div className="cart-name">
{line_item.variant.name}
</div>
<div className="cart-price">{line_item.variant.price}</div>
</div>
<div className="cart-qty">
<div className="cart-qty-name">QTY:</div>
<div className="cart-qty-value">
<div class="minus"><span>-</span></div>
{line_item.quantity}
<div class="plus">
// used arrow function
<span value = { line_item.variant.id } onClick={() => props.dispatch(addToCart(line_item.variant.id, 1)} >+</span></div>
</div>
</div>
<div className="cart-total">
<div className="cart-total-name">Total</div>
<div className="cart-total-value">{line_item.variant.price * line_item.quantity}</div>
</div>
</div>
</li>
</ul>
</div>
)
}
export default connect()(MyComponent); // connect dispatch to component