How to Read mutliple images with FileReader - javascript

I Wanna Select Multiple Image from one input And Read It With File Reader , and if i leave it like this, it give me one picutre
const [image , setImage] = useState('');
const [imageSelected , setImageSelected] = useState(null);
const onImageChange = event => {
const reader = new FileReader();
reader.onload = () => {
if(reader.readyState === 2){
setImageSelected(reader.result)
console.log(reader.result)
}
}
setImage(event.target.files[0]);
reader.readAsDataURL(event.target.files[0])
console.log(image)
}
HTML
<label htmlFor="image" className = "col-span-3 ">
{
!imageSelected ? <PhotoCameraIcon fontSize="120" className ="border rounded p-2 h-24 text-8xl text-gray-600 cursor-pointer" /> : (
<img src={imageSelected} alt="" className = "h-44" />
)
}
<input hidden multiple onChange={onImageChange} type="file" name="image" id="image" />
</label>

import "./styles.css";
import React, {Component} from 'react';
export default class App extends Component {
constructor (props){
super(props);
this.state={
images: null
}
}
readFileContents = async (file) => {
return new Promise((resolve, reject) => {
let fileReader = new FileReader();
fileReader.onload = () => {
resolve(fileReader.result);
};
fileReader.onerror = reject;
fileReader.readAsDataURL(file);
});
}
readAllFiles = async (AllFiles) => {
const results = await Promise.all(AllFiles.map(async (file) => {
const fileContents = await this.readFileContents(file);
return fileContents;
//let a = URL.createObjectURL(fileContents);
//return a;
}));
console.log(results, 'resutls');
return results;
}
handleUpload = (e) => {
let AllFiles = [];
[...e.target.files].map(file => AllFiles.push(file));
this.readAllFiles(AllFiles).then(result => {
let allFileContents = [];
result.map(res =>{
allFileContents.push(res);
})
this.setState({images: allFileContents});
}).catch(err => {
alert(err);
});
}
render = () => {
return (<div>
<input type="file" multiple onChange={(e) => this.handleUpload(e)}/>
{this.state.images && this.state.images.map((img, idx)=>{
return <img width={100} height={50} src={img} alt={idx} key={idx} />
})
}
</div>
)
}
}

Related

Show loading spinner tilll the image is fully loaded (prevent printing image effect) React.js

I have background image that loads as it is like printing even if i'm using loading spinner (to make the content visible only when the image is got from the API). How can i prevent it, i tried using loading="lazy" properties but still not success.
App.js (newLoader state is used to set the image on response from api)
import { useEffect, useState } from 'react';
import './App.css';
import Forcast from './components/Forcast';
import Loader from './components/Loader';
import Weather from './components/Weather';
function App() {
// States
const [loader, setLoader] = useState(true);
const [newLoader, setNewLoader] = useState(true);
const [lat, setLat] = useState(0);
const [long, setLong] = useState(0);
const [weatherData, setWeatherData] = useState("");
const [forcastData, setForcastData] = useState([]);
const [photos, setPhotos] = useState([]);
const [country, setCountry] = useState("");
useEffect(() => {
//Function to call apis for weather, forcast and unsplash
const weatehr = async () => {
// todayWeather
navigator.geolocation.getCurrentPosition((position) => {
setLat(position.coords.latitude);
setLong(position.coords.longitude);
})
if (lat && long !== 0) {
// getting the current weatehr
await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&units=metrics&appid=${process.env.REACT_APP_API_KEY}`)
.then((res) => res.json())
.then((data) => {
setWeatherData(data)
})
.catch((err) => {
alert(err.message)
})
// getting the random image from unsplash
fetch(`https://api.unsplash.com/search/photos?query={landscape}&orientation=landscape&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}`)
.then((res) => res.json())
.then((data) => {
const imageUrlsAre = data.results.map((item) => item.urls.full)
const randomImage = Math.floor(Math.random() * imageUrlsAre.length);
setPhotos(imageUrlsAre[randomImage])
})
.then(() => {
setNewLoader(false)
})
.catch((err) => err)
// for forcast of 5 days
await fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${long}&exclude=current,minutely,hourly,alerts&units=metrics&appid=${process.env.REACT_APP_API_KEY}`)
.then((res) => res.json())
.then((data) => {
setLoader(false)
// for getting country name
if (data && data.city) {
const coutntryForcast = data.city.country;
setCountry(coutntryForcast)
}
// for getting the forcast
const arrayForcast = data.list;
if (arrayForcast) {
let midday = []
for (let i = 0; i < arrayForcast.length; i++) {
let dates = arrayForcast[i].dt_txt.substring(10);
let days = arrayForcast[i].dt_txt.slice(0, 10);
let icon = arrayForcast[i].weather[0].icon;
let temp = arrayForcast[i].main
if ((dates.indexOf("12:00:00") > -1) === true) {
midday.push({ temp, days, icon })
}
}
midday.shift()
setForcastData(midday)
}
})
.catch((err) => {
alert(err.message)
})
}
}
weatehr()
}, [lat, long])
return (<>
{loader === true ? <Loader /> :
<>
{newLoader === true ? <Loader /> :
<div className="App">
<div className='image__wrapper'>
<img alt='background' src={photos && photos}
loading="lazy"
/>
<div className='overlay'>
</div>
</div>
<div className='app__body'>
<div className='today__weather'>
{weatherData.cod === 200 ? <Weather weatherData={weatherData} photo={photos} country={country} forcastData={forcastData} /> : <div className='error_message'> No weather</div>}
</div>
<div className='forcast'>
{weatherData.cod === 200 ? <Forcast weatherData={weatherData} forcastData={forcastData} /> : <div className='error_message'></div>}
</div>
</div>
</div>}
</>
}
</>
);
}
export default App;

How to save the value of a variable converted to base64?

I am using a .zip file with thousands of geographical coordinates and converting to base64.
I can convert the file to base64, the problem is to save the result of this variable for later use.
I'm trying to use setState to save the variable's value but nothing happens.
Can you tell me what I'm doing wrong?
Here's my code I put in codesandbox
And here the zilFile I'm converting
const [zipFile, setZipFile] = useState("");
const [base64, setBase64] = useState("");
const getBase64 = (file, cb) => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
cb(reader.result);
};
reader.onerror = function (error) {};
};
const toBase64 = async () => {
let auxZip = "";
await getBase64(zipFile, (result) => {
auxZip = result.substring(28);
console.log("auxZip: ", auxZip);
setBase64(auxZip);
});
};
const onSave = () => {
toBase64();
console.log("base64: ", base64);
};
const handleZipChangle = (event) => {
const file = event.target.files[0];
setZipFile(file);
};
I have fixed like this, it worked perfectly, please take a look.
import React, { useState } from "react";
import "./styles.css";
import FormControl from "#material-ui/core/FormControl";
import Typography from "#material-ui/core/Typography";
export default function App() {
const [base64, setBase64] = useState("");
const getBase64 = (file, cb) => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = (e) => {
cb(e.target.result);
};
reader.onerror = function (error) {};
};
const onSave = () => {
console.log("base64: ", base64);
};
const handleZipChangle = (event) => {
const file = event.target.files[0];
let auxZip = "";
getBase64(file, (result) => {
auxZip = result.substring(28);
setBase64(auxZip);
});
};
return (
<div className="App">
<FormControl>
<Typography>Select Zip File:</Typography>
<input
accept="zip/*"
type="file"
id="contained-button-file"
onChange={handleZipChangle}
/>
</FormControl>
<div style={{ marginTop: "30px" }}>
<button onClick={onSave}>SAVE</button>
</div>
</div>
);
}
or if you want to use zip file, you can use useEffect to check the state loaded and call getBase64
useEffect(() => {
let auxZip = "";
zipFile &&
getBase64(zipFile, (result) => {
auxZip = result.substring(28);
setBase64(auxZip);
});
}, [zipFile]);
const onSave = () => {
console.log("base64: ", base64);
};
const handleZipChangle = (event) => {
const file = event.target.files[0];
setZipFile(file);
};
Your auxZip has been set. Cause function toBase64 is async, the auxZip is empty.
You can check by:
const toBase64 = async () => {
let auxZip = "";
getBase64(zipFile, (result) => {
auxZip = result.substring(28);
// console.log("auxZip: ", auxZip);
setBase64(auxZip);
});
};
console.log(base64);
const onSave = async () => {
await toBase64();
console.log("base64: ", base64);
};

Refactoring React class to hooks - Entity update component

I have this React component that I use to update business entities. It basically fetches by ID on componentDidMount and sends a put request when the form is submitted. I would like to refactor this to a hook based component.
Here is the code before
import React from "react";
import axios from "axios";
//Api Helper Methods
const API_HOST = "https://api.example.com";
const get = (endPoint) =>
axios
.get(`${API_HOST}/${endPoint}`)
.then((response) => response.data);
export const put = (endPoint, payload, id) =>
axios
.put(`${API_HOST}/${endPoint}/${id}`, payload)
.then((response) => response.data);
//React route (uses React Router)
const END_POINT = `users`;
class Entity extends React.Component {
state = { entity: {}, fetching: true };
getEntity = async () => {
const { id } = this.props.match.params;
this.setState({ fetching: true });
const entity = await get(`${END_POINT}/${id}`);
this.setState({ entity, fetching: false });
};
onChange = (key, value) =>
this.setState({ entity: { ...this.state.entity, [key]: value } });
componentDidMount() {
this.getEntity();
}
onSubmit = async (e) => {
e.preventDefault();
let { entity } = this.state;
let { match } = this.props;
await put(END_POINT, entity, match.params.id);
};
render() {
const { entity, fetching } = this.state;
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={this.onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => this.onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}
}
export default Entity;
This is what I have so far for the code after. Next step would be to extract custom hook.
const END_POINT = `users`;
export default function Entity({ match }) {
const [entity, setEntity] = useState({ name: "" });
const [fetching, setFetching] = useState( true );
const { id } = match.params;
const onChange = (key, value) => setEntity({ ...entity, [key]: value });
useEffect(() => {
const fetchEntity = async () => {
const entity = await get(`${END_POINT}/${id}`);
setEntity(entity);
setFetching(false);
};
fetchEntity();
}, [id]);
const onSubmit = async (e) => {
e.preventDefault();
await put(END_POINT, entity, id);
};
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}
I haven't tested this but this should be close to what you want with a custom hook for your entity function.
import React, { useEffect, useState } from 'react';
const API_HOST = "https://api.example.com";
const END_POINT = `users`;
function useEntity(entityID) {
const [entity, setEntity] = useState({})
useEffect(() => {
(async () => {
await fetch(`${API_HOST}/${END_POINT}/${props.match.params}`)
.then(async res => await res.json())
.then(result => setEntity(result));
})();
}, [])
return entity
}
export default function Entity(props) {
const { id } = props.match;
const entity = useEntity(id);
const onSubmit = async () => await fetch(`${API_HOST}/${END_POINT}/${id}`, {method: 'PUT', body: entity})
if (!entity) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => setEntity({ ...entity, name: e.target.value})}
/>
<button type="submit">submit</button>
</form>
)
}
Thanks for the help Harben, I got it working like this.
import React, {useEffect, useState} from "react";
import axios from "axios";
//Api Helper Methods
const API_HOST = "https://api.example.com";
const get = (endPoint) =>
axios.get(`${API_HOST}/${endPoint}`).then((response) => response.data);
export const put = (endPoint, payload, id) =>
axios
.put(`${API_HOST}/${endPoint}/${id}`, payload)
.then((response) => response.data);
const END_POINT = `users`;
const useEntity = (entityId) => {
const [entity, setEntity] = useState({ name: "" });
const [fetching, setFetching] = useState(true);
useEffect(() => {
(async () => {
const entity = await get(`${END_POINT}/${entityId}`);
setEntity(entity);
setFetching(false);
})();
}, [entityId]);
return [entity, fetching, setEntity];
};
//React route (uses React Router)
export default function Entity({ match }) {
const { id } = match.params;
const [entity, fetching, setEntity] = useEntity(id);
const onChange = (key, value) => setEntity({ ...entity, [key]: value });
const onSubmit = async (e) => {
e.preventDefault();
await put(END_POINT, entity, id);
};
if (fetching) {
return <p>loading...</p>;
}
return (
<form onSubmit={onSubmit}>
<label htmlFor="name">name</label>
<input
value={entity["name"]}
onChange={(e) => onChange("name", e.target.value)}
/>
<button type="submit">submit</button>
</form>
);
}

ReactJS App doesn't update data without refreshing browser

While my code works from the functionalities, I have to click "refresh" after each click to see the changes. For example when I click "Add note" I have to refresh the page in order to see it. While it compiles successfully, the console shows three errors:
import { API, graphqlOperation } from "aws-amplify";
import { withAuthenticator } from "aws-amplify-react";
import React, { useEffect, useState } from "react";
import { createNote, deleteNote, updateNote } from "./graphql/mutations";
import { listNotes } from "./graphql/queries";
import {
onCreateNote,
onDeleteNote,
onUpdateNote
} from "./graphql/subscriptions";
const App = () => {
const [id, setId] = useState("");
const [note, setNote] = useState("");
const [notes, setNotes] = useState([]);
useEffect(() => {
getNotes();
const createNoteListener = API.graphql(
graphqlOperation(onCreateNote)
).subscribe({
next: noteData => {
const newNote = noteData.value.data.onCreateNote;
setNotes(prevNotes => {
const oldNotes = prevNotes.filter(note => note.id !== newNote.id);
const updatedNotes = [...oldNotes, newNote];
return updatedNotes;
});
setNote("");
}
});
const deleteNoteListener = API.graphql(
graphqlOperation(onDeleteNote)
).subscribe({
next: noteData => {
const deletedNote = noteData.value.data.onDeleteNote;
setNotes(prevNotes => {
const updatedNotes = prevNotes.filter(
note => note.id !== deletedNote.id
);
return updatedNotes;
});
}
});
const updateNoteListener = API.graphql(
graphqlOperation(onUpdateNote)
).subscribe({
next: noteData => {
const updatedNote = noteData.value.data.onUpdateNote;
setNotes(prevNotes => {
const index = prevNotes.findIndex(note => note.id === updatedNote.id);
const updatedNotes = [
...prevNotes.slice(0, index),
updatedNote,
...prevNotes.slice(index + 1)
];
return updatedNotes;
});
setNote("");
setId("");
}
});
return () => {
createNoteListener.unsubscribe();
deleteNoteListener.unsubscribe();
updateNoteListener.unsubscribe();
};
}, []);
const getNotes = async () => {
const result = await API.graphql(graphqlOperation(listNotes));
setNotes(result.data.listNotes.items);
};
const handleChangeNote = event => setNote(event.target.value);
const hasExistingNote = () => {
if (id) {
const isNote = notes.findIndex(note => note.id === id) > -1;
return isNote;
}
return false;
};
const handleAddNote = async event => {
event.preventDefault();
// Check if we have an exisiting note. If so, then update it.
if (hasExistingNote()) {
handleUpdateNote();
} else {
const input = { note };
await API.graphql(graphqlOperation(createNote, { input }));
}
};
const handleUpdateNote = async () => {
const input = { id, note };
await API.graphql(graphqlOperation(updateNote, { input }));
};
const handleDeleteNote = async noteId => {
const input = { id: noteId };
await API.graphql(graphqlOperation(deleteNote, { input }));
};
const handleSetNote = ({ note, id }) => {
setNote(note);
setId(id);
};
return (
<div className="flex flex-column items-center justify-center pa3 bg-washed-red">
<h1 className="code f2-l">Amplify Notetake</h1>
{/* Note Form */}
<form onSubmit={handleAddNote} className="mb3">
<input
type="text"
className="pa2 f4"
placeholder="Write your note"
onChange={handleChangeNote}
value={note}
/>
<button className="pa2 f4" type="submit">
{id ? "Update note" : "Add note"}
</button>
</form>
{/* Notes list */}
<div>
{notes.map(item => (
<div key={item.id} className="flex items-center">
<li onClick={() => handleSetNote(item)} className="list pa1 f3">
{item.note}
</li>
<button
onClick={() => handleDeleteNote(item.id)}
className="bg-transparent bn f4"
>
<span>×</span>
</button>
</div>
))}
</div>
</div>
);
};
export default withAuthenticator(App, { includeGreetings: true });
If you are using CLI version 2.0 and above, owner is a required argument. This is explained more in the link below:
https://aws-amplify.github.io/docs/cli-toolchain/graphql#authorizing-subscriptions
After I added Auth in the import
import { API, graphqlOperation, Auth } from 'aws-amplify';
captured the current user and passed it into the subscription it started working for me.
useEffect(() => {
getNotes();
const owner = Auth.user.getUsername();
const createNoteListener = API.graphql(
graphqlOperation(onCreateNote, { owner })
).subscribe({
next: noteData => {
const newNote = noteData.value.data.onCreateNote;
setNotes(prevNotes => {
const oldNotes = prevNotes.filter(note => note.id !== newNote.id);
const updatedNotes = [...oldNotes, newNote];
return updatedNotes;
});
setNote("");
}
});

How to set backgroundImage from input file?

I hope to set background image from input local file.
But it occurs 'net::ERR_UNKNOWN_URL_SCHEME' error message.
My input tag:
<input
accept="image/*"
className="input_img"
type="file"
onChange={e => this.uploadImage(e)}
/>
My uploadImage function:
uploadImage = e => {
let node = document.getElementById("result");
node.style.backgroundImage = "url(" + e.target.result + ")";
};
How do I do it?
You could use a FileReader to read the data of the file, and then set the backgroundImage with the result.
Example
class App extends Component {
uploadImage = (e) => {
const { files } = e.target;
if (files.length === 0) {
return;
}
const file = files[0];
const fileReader = new FileReader();
fileReader.onload = () => {
this.background.style.backgroundImage = `url(${fileReader.result})`;
};
fileReader.readAsDataURL(file);
};
render() {
return (
<div>
<input
accept="image/*"
className="input_img"
type="file"
onChange={this.uploadImage}
/>
<div
style={{width: 200, height: 200}}
ref={ref => this.background = ref}
></div>
</div>
);
}
}

Categories