<Image source={require(" ")} /> not displaying correctly? - javascript

Im confused that my Image is not being displayed.
This works but its a bit too static. I need a dynamic profile-picture update when uploading a file.
import picture from "../../images/public/600bc441b2b2b62c542bd135profilepicture.jpg";
return(
<div>
<Image className={"profilepicture"} source={picture} alt={"pic"} />
</div>
)
So I implemented it with my Backend-Axios-Call like this:
const [mapimages, setMapImages] = useState(null);
useEffect(() => {
axios.get(API_BASE_URL + '/user/images', payload)
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
const files = response.data.files[0];
const requireimg = require("../../images/public/" + files);
setMapImages(<Image source={requireimg} alt={"TEXT"} />);
} else {
alert("error getting images");
}
})
.catch(function (error) {
console.log("DOWNLOAD: " + error);
});
}, []);
return(
<div>
{mapimages}
</div>
)
Sadly I dont get the Images displayed. It shows the correct path to the File though.
This is the path in my image inspector:
<img alt="TEXT" class="profilepicture" source="/static/media/600bc441b2b2b62c542bd135profilepicture.8a22cb97.jpg">
and navigating
from
http://localhost:3000/#/profile
to
http://localhost:3000/static/media/600bc441b2b2b62c542bd135profilepicture.8a22cb97.jpg
also displays the Image.
I always get this:
I'm clueless because this previously worked. I just forgot to push it to git :(

You should try to replace "source" with "src" inside your image tag

Related

Image not rendering in my Admin application

I am creating a admin application where i want to display uploaded images of product stored in database. I have uploaded images as an object id in MongoDB. But the image container in admin app displays the number of images stored in database. But the images are not displayed. I tried using absolute URL too but that doesnot work either.
Here is my code to upload images:
{productPictures.length > 0
? productPictures.map((pic, index) => (
<div key={index}>{pic.name}</div>
))
: null}
<input
type="file"
name="productPictures"
onChange={handleProductPictures}
/>
Here is the code to display images:
<label className="key">Product Pictures</label>
<div style={{ display: "flex" }}>
{productDetails.productPictures.map((picture) => (
<div className="productImgContainer">
<img src={generatePublicUrl(picture.img)} alt="" />
</div>
))}
</div>
Generate URL function looks like this:
const api ='http://localhost:2000/'
// const api = 'http://192.168.0.104:2000/'
const generatePublicUrl = (fileName) => {
return `http://localhost:2000/src/uploads/products/${fileName}`;
}
export {
api,
generatePublicUrl
};
Function to save product in database:
const createProduct= (req, res) => {
const { name, price, description, category, quantity, createdBy } = req.body;
let productPictures = [];
if (req.files.length > 0) {
productPictures = req.files.map((file) => {
return { img: file.location };
});
}
const product = new Product({
name: name,
slug: slugify(name),
price,
quantity,
description,
productPictures,
category,
createdBy: req.user._id,
});
product.save((error, product) => {
if (error) return res.status(400).json({ error });
if (product) {
res.status(201).json({ product, files: req.files });
}
});
}
The uploaded images in program looks like this:
Open image here
But the page displays blank area and filename shows undefined when inspected.
Open image here
I believe you are trying to add a non-public path to the source.
you need to add the files to the public folder so you can call assets using the path , otherwise you can import the images and then add them to the src attribute
Edit 1:
return `http://localhost:2000/src/uploads/products/${fileName}`;
this will not work , you can't access what inside the src
the only folder you can access it is the public folder

React component renders before I can set src of image

I have this application that flashes a series of cards. Some have questions with text. No problem there obviously. But the image source is being retrieved from firebase. On each render I check if it has a question with text, or with an image and if it has an image I query the database for the downloadURL and insert that as the source. If I insert it hard coded it works fine, if I console log the response it's accurate. My problem is I believe that the component renders before I can insert the source dynamically. Code is below. And yes, I know with that many conditionals it looks like a christmas tree and is probably really bad practice.
To save some reading I'll splice it where I make the request here...
useEffect(() => {
if ("imageHolder" in active) {
const asyncFunc = async () => {
setLoading(true);
setImage(true);
await storageRef
.child(active.imageHolder)
.getDownloadURL()
.then(function (url) {
imageSrc = url;
console.log("url returns ", url);
})
.catch(function (error) {
console.log(error);
});
};
asyncFunc();
setLoading(false);
}
}, [active, getQuestions, correctAnswer]);
And where I insert it here
) : image ? (
loading ? (
<h1>Loading</h1>
) : (
<img alt="" src={imageSrc} className="d-inline-block align-top" />
)
) : (
<h3>{active.question}</h3>
)}
</div>
<div className="answerGrid">
{loading ? (
Thanks for any advice at all. And stay healthy!
It might be helpful to see the rest of the code, but given the provided snippets, I'm assuming the problem is with how the imageSrc variable is getting set.
Have you tried managing the imageSrc as state? E.g.
const [imageSrc, setImageSrc] = useState('')
// then use setImageSrc after getting the url
await storageRef
.child(active.imageHolder)
.getDownloadURL()
.then(function (url) {
setImageSrc(url)
console.log("url returns ", url);
})
I think simple decision to this will be adding a logical "or" operator in src
like this
<img alt="" src={imageSrc || ''} className="d-inline-block align-top" />

Force fetched image data to https

I am looking for a solution to force images from a fetch API to be in https rather than http
The API returns image results as http from the fetched JSON file but this is giving warning in the console to Mixed Content
I am fetching in componentDidMount as
componentDidMount() {
var self = this;
const proxyurl = 'https://cors-anywhere.herokuapp.com/';
const url = `//api.tripadvisor.com/api/partner/2.0/location/${this.props
.tripAdvisorId}?key=${AuthKey}`;
fetch(proxyurl + url)
.then(data => data.json())
.then(data => {
self.setState({
reviewData: data,
isLoading: false
});
});
}
and then mapping the data by way
{this.state.reviewData.reviews.map(i => {
return (
<div key={i.id}>
<img src={i.rating_image_url} alt={i.title} />
</div>
);
})}
How can I force the url from {i.rating_image_url} to use https when this is not returned from the fetch?
By using a regular expression, something like:
{this.state.reviewData.reviews.map(i => {
return (
<div key={i.id}>
<img src={i.rating_image_url.replace(/^http:\/\//i, 'https://')} alt={i.title} />
</div>
);
})}
const url = new URL(originalUrl);
url.protocol = url.protocol.replace('http', 'https');
console.log(url.href);
This method uses the built-in URL class to fully parse, and then uses a string replacement on the protocol.
Just change this code to check if you are receiving the image or not
<img src={i.rating_image_url ? i.rating_image_url : i.rating_image_url.replace(/^http:\/\//i, 'https://')} alt={i.title} />
This way we are checking if we are getting its value or not.
For more better understanding you can also do this
{this.state.reviewData.reviews.map(i => {
console.log(i.rating_image_url);
return (
<div key={i.id}>
<img src={i.rating_image_url} alt={i.title} />
</div>
);
})}
This will show whatever data you are receiving in rating_image_url on your browser console.
Hope it helps you.

Decode QR Code Image from Camera Roll React Native

I'm trying to implement a feature in my app where I the user can select a picture from their camera roll and the app will decode a QR code in the image is detected.
I'm currently using react-native-camera-roll-picker: https://github.com/jeanpan/react-native-camera-roll-picker
and react-native-qrcode-local-image: https://github.com/remobile/react-native-qrcode-local-image
The problem is the local QR code image library wants me to pass a local path and isn't compatible with the native uri provided by react-native-camera-roll-picker. I would use another library for decoding the image QR code but this one appears to be the only one that works on iOS and Android and scans from existing images rather than from the actual camera.
I've also tried implementing react-native-fetch-blob in order to temporarily save the camera roll image locally, but that's been giving me trouble as well: https://github.com/wkh237/react-native-fetch-blob
This is my current attempt in a function that I call in the "callback" prop for react-native-camera-roll-picker (with previous attempts commented out):
_pickedImage(array,currentImg) {
console.log(currentImg)
var path = RNFS.DocumentDirectoryPath + '/pickedqr';
let rnfbURI = RNFetchBlob.wrap(RNFetchBlob.fs.asset(currentImg.uri))
const Blob = RNFetchBlob.polyfill.Blob
Blob.build(rnfbURI, {type:'image/jpg'}).then((b) => {
tmpBlob = b;
RNFetchBlob.fs.readFile(tmpBlob, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
});
})
/*fullPath = currentImg.uri.replace("assets-library://", "cdvfile://localhost/assets-library/")
QRDecoder.decode(fullPath, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});*/
/*let blb = Blob.build( rnfbURI, { type: 'image/jpg'})
console.log(blb)*/
/*RNFetchBlob.fs.readFile(rnfbURI, 'base64').then((data) => {
console.log("Base64", data)
QRDecoder.decode(`data:image/gif;base64,${data}`, (error, result)=>{
console.log("Code", result)
console.log("Error", error)
});
})*/
}
I'm at a total loss at the moment so any methods or insight would be much appreciated.
you can use react-native-qrcode-scanner to scan QR from images or directly through the camera.
INSTALLATION:
install dependency by using this command:
yarn add react-native-camera react-native-qr-scanner
link those libraries by using:
react-native link react-native-camera && react-native-qr-scanner
you need to add the permission to your AndroidManifest.xml of your project. This should be found in your android/app/src/main/AndroidManifest.xml Add the following:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE"/>
With iOS 10 and higher, you need to add the "Privacy - Camera Usage Description" key to the info.plist of your project. This should be found in your_project/ios/your_project/Info.plist. Add the following code:
<key>NSCameraUsageDescription</key>
<string/>
<key>NSPhotoLibraryUsageDescription</key>
<string/>
<key>NSMicrophoneUsageDescription</key>
<string/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string/>
Usage:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {QRreader} from 'react-native-qr-scanner';
import ImagePicker from 'react-native-image-picker';
export default class Scanner extends Component {
constructor(props) {
super(props);
this.state = {
reader: {
message: null,
data: null
}
};
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={()=>{
this.openPhoto();
}}>
<Text style={{marginTop: 20}}>打开相册识别二维码</Text>
</TouchableOpacity>
<View>
{!this.state.reader? <Text>{!this.state.reader.message?'':`${this.state.reader.message}`}</Text>: <Text>{!this.state.reader.message?'':`${this.state.reader.message}:${this.state.reader.data}`}</Text>}
</View>
</View>
);
}
openPhoto(){
console.log('ImagePicker');
ImagePicker.launchImageLibrary({}, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
if(response.uri){
var path = response.path;
if(!path){
path = response.uri;
}
QRreader(path).then((data)=>{
this.setState({reader: {
message: '识别成功',
data: data
}});
// 十秒后自动清空
setTimeout(() => {
this.setState({reader: {
message: null,
data: null
}})
}, 10000);
}).catch((err)=>{
this.setState({reader: {
message: '识别失败',
data: null
}});
});
}
}
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff'
}
});
you can read more about this library here: https://www.npmjs.com/package/react-native-qr-scanner
You can use react-native-camera to solve this issue easily.
Here's the simple code snippet for that.
handleCodeDetected = (data) => {
// do whatever you want to do with data
}
...
...
<RNCamera
type={RNCamera.Constants.Type.back}
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
onBarCodeRead={this.handleCodeDetected}
style={styles.preview}
/>
This answer solved it for me.
Created native method to covert uri in path, here is my code:
#ReactMethod
public void getRealPathFromURI(String contentUriString, Promise promise) {
Uri contentUri = Uri.parse(contentUriString);
Cursor cursor = null;
try {
String wholeID = DocumentsContract.getDocumentId(contentUri);
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
String sel = MediaStore.Images.Media._ID + "=?";
cursor = reactContext.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
int columnIndex = cursor.getColumnIndex(column[0]);
String filePath = "";
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
promise.resolve(filePath);
} catch (Throwable e) {
promise.reject(e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
And js:
DocumentPicker.pick({ type }).then((document: DocumentPickerResponse) => {
MyNativeModule.getRealPathFromURI(document.uri).then((path) => {
QRCodeLocalImage.decode(path, (err, res) => {
callback(err, { qrData: res });
});
});
});
You can just use react-native-rn-zxing:
npm i react-native-rn-zxing
then link it :
react-native link react-native-rn-zxing
Usage :
import RnZxing from 'react-native-rn-zxing';
...
// Pass the callback as a parameter
RnZxing.showQrReader(this.onBarcodeScanned);
...
// Define the callback function to handle data after scan
onBarcodeScanned = (data) => {
this.setState({data: data});
};
You can use rn-qr-generator
It can detect QR code in image
RNQRGenerator.detect({
uri: PATH_TO_IMAGE, // local path of the image. Can be skipped if base64 is passed.
base64: imageBase64String, // If uri is passed this option will be skipped.
})
.then(response => {
const { values } = response; // Array of detected QR code values. Empty if nothing found.
})

How to add a loading indicator on every Relay.js network request

I'm currently building a Relay/React web app. It's been amazingly simple with one exception. I've not been able to figure out how I can get a global notification when any of my components are making network requests. I'm hopping to add a spinner to the top of my app when ever there's network activity, because some of my mutations take a long time to load.
This was my attempt at solving this problem, but it only works on new route page loads.
function renderer(info)
{
let {props, error, element} = info;
if (error) {
return (<ServerError errors={error}/>);
} else {
if (props) {
return React.cloneElement(element, props);
} else {
return (<Loading />);
}
}
}
ReactDOM.render(
<Router
history={browserHistory}
render={applyRouterMiddleware(useRelay)}
environment={Relay.Store}
>
<Route
path="/"
queries={ViewerQuery}
component={App}
>
<IndexRoute
queries={ViewerQuery}
component={Libraries}
render={renderer}
/>
<Route path="*" component={Error}/>
</Route>
</Router>
Ideally I could get some callback that I can pass to my App component, which renders all my pages headers and footers. Any help with this would be greatly appreciated. I've been all over the internet for a while trying to find a good solution to this.
You could also try adding a custom Relay Network Layer that renders the loading indicator component on every request. I think the main concern to take into account for the "global" loading indicator is about design not only of the indicator but also about its impact on the UI globally. Is it going to block the UI?, just one part of it?, will it displace the other elements up/down?, etc.
In the meantime, you can do something like:
handleSubmit(event) {
event.preventDefault();
this.setState({isLoading: true});
this.props.relay.commitUpdate(
new LoginMutation({
email: this.refs.email.value,
password: this.refs.password.value
}), {
onSuccess: response => {
Auth.login(response.login.accessToken);
const { location, router } = this.props;
if (location.state && location.state.nextPathname) {
router.replace(location.state.nextPathname)
} else {
router.replace('/')
}
},
onFailure: transaction => {
this.setState({hasError: true});
this.setState({isLoading: false});
}
}
);
}
The above is snippet is taken from here. You can see the rest of the logic in that repo.
You can create a custom spinner component in react and based on your data load status you can either show or hide the spinner.
An example for this can be -
Your Spinner component could be like this -
let SpinMe
= (
<div className="spinner-container">
<div className="loader">
<svg className="circular">
<circle className = "path"
cx = "50"
cy = "50"
r = "20"
fill = "none"
strokeWidth = "3"
strokeMiterLimit = "10"
/>
</svg>
</div>
</div>
);
This spinner component should have somewhat higher z-index than other component so that while loading is occurring user can not click other components or interact with other components.
Also in styling show some transparent dark background of spinner.
e.g
.spinner-container {
position : absolute;
background-color : rgba(12, 12, 12, 0.61);
width : 100%;
min-height : 100%;
background-size : 100% 100%;
text-align : center;
z-index : 3;
top : 0;
left : 0;
}
Now Your another component where you want to use the spinner and in this component you want to make network request.
import React from 'react';
class SpinTestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading:false
};
}
sendNetworkRequest(URL, dataToSend) {
return $.ajax({
type : 'POST',
url : URL,
data : JSON.stringify(dataToSend),
dataType : 'json'
});
}
componentDidMount() {
const URL = "test url";
const dataToSend = { param1:"val", param2:"val" };
this.setState({isLoading:true});
this.sendNetworkRequest(dataToSend)
.then(
() => {
// success response now remove spinner
this.setState({isLoading:false});
},
() => {
// error response again remove spinner and
// show error message to end user
this.setState({isLoading:false});
});
}
render() {
return (
<div>
{ this.state.isLoading ? <SpinMe/> : null }
<div>
<h1>
Remaining Component structure
or Jsx
</h1>
<p>
To be show after loading is done.
</p>
</div>
</div>
);
}
}
export default SpinTestComponent;
I ended up extending Relay's default network layer so that I could make some Flux events that my main root component listens to. This allows me to have all my loading and error message handling in one place if I so desire.
Here's my final solution. Not sure that it's the cleanest it could be, but it works quite well.
import Relay from "react-relay";
import RelayMutationRequest from "react-relay/lib/RelayMutationRequest";
import AppDispatcher from "./AppDispatcher";
export default class CustomNetworkLayer extends Relay.DefaultNetworkLayer {
constructor(uri, init)
{
super(uri, init);
}
networkLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'LOADING'
});
}
networkDoneLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'DONE_LOADING'
});
}
networkErrorEvent(error)
{
AppDispatcher.dispatch({
actionType: 'ERROR',
payload: error
});
}
sendQueries(requests)
{
this.networkLoadingEvent();
return Promise.all(requests.map(request => (
this._sendQuery(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
if (!payload.hasOwnProperty('data')) {
const error = new Error(
'Server response was missing for query ' +
`\`${request.getDebugName()}\`.`
);
this.networkErrorEvent(error);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
)
)));
}
sendMutation(request)
{
this.networkLoadingEvent();
return this._sendMutation(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
);
}
/**
* Formats an error response from GraphQL server request.
*/
static formatRequestErrors(request, errors)
{
const CONTEXT_BEFORE = 20;
const CONTEXT_LENGTH = 60;
const queryLines = request.getQueryString().split('\n');
return errors.map(({locations, message}, ii) =>
{
const prefix = (ii + 1) + '. ';
const indent = ' '.repeat(prefix.length);
//custom errors thrown in graphql-server may not have locations
const locationMessage = locations ?
('\n' + locations.map(({column, line}) =>
{
const queryLine = queryLines[line - 1];
const offset = Math.min(column - 1, CONTEXT_BEFORE);
return [
queryLine.substr(column - 1 - offset, CONTEXT_LENGTH),
' '.repeat(Math.max(0, offset)) + '^^^',
].map(messageLine => indent + messageLine).join('\n');
}).join('\n')) :
'';
return prefix + message + locationMessage;
}).join('\n');
}
static createRequestError(request, responseStatus, payload)
{
const requestType =
request instanceof RelayMutationRequest ? 'mutation' : 'query';
const errorReason = typeof payload === 'object' ?
CustomNetworkLayer.formatRequestErrors(request, payload.errors) :
`Server response had an error status: ${responseStatus}`;
const error = new Error(
`Server request for ${requestType} \`${request.getDebugName()}\` ` +
`failed for the following reasons:\n\n${errorReason}`
);
error.source = payload;
error.status = responseStatus;
return error;
}
}
then in my index.js file I do this:
Relay.injectNetworkLayer(new CustomNetworkLayer("/graphql",
{
fetchTimeout: 35000, // timeout after 35 seconds
retryDelays: [2000] // retry after 2 seconds
}));
quick note: AppDispatcher is just a flux js dispatcher, and I'm listening to those events in my main wrapper component.
hope this helps someone else out. I certainly spent too much time on this.
Also thank you to everyone who helped me come to this solution.

Categories

Resources