How to render svg file in react? - javascript

I want to upload a svg file and show preview in react, but I don't know how to convert a svg file into react component. I try to use DOMParser to parse svg-xml string to Dodument Object, but it is not working.
import { useState } from 'react';
import { Upload, Button, Card } from 'antd';
import { UploadChangeParam } from 'antd/lib/upload/interface';
import 'antd/dist/antd.css';
function App() {
const [svgs, setSvgs] = useState<Document[]>([]);
const handleChange = async ({ file }: UploadChangeParam) => {
console.log(file);
let domparser = new DOMParser();
const svg = (await file.originFileObj?.text()) ?? '';
const ele = domparser.parseFromString(svg, 'image/svg+xml');
setSvgs([...svgs, ele]);
};
return (
<div style={{ margin: 50 }}>
<Upload name="file" showUploadList={false} onChange={handleChange}>
<Button>Upload</Button>
</Upload>
{/* preview list */}
<Card style={{ marginTop: 20 }}>
{svgs.map((SVGComponent) => {
return <SVGComponent />;
})}
</Card>
</div>
);
}
export default App;

You can use following library to convert svg's. You can also add its cli commands to your package.json
https://react-svgr.com/playground/

Related

How to display all images from firebase storage on React Native app?

I can upload pictures to FB storage. But now I'm trying to display them all on React Native app live.
For some reason, I can't make it work. There are not lots of videos on youtube or recent tutorials on how to do this. I'm trying to make it work by looking it up on Stackoverflow from people who had some similar problems, but no luck so far.
Here's my app code
import { StyleSheet, View } from 'react-native';
import Uploadscreen from './src/UploadSreen';
import ListPictures from './src/ListPictures';
export default function App() {
return (
<View style={styles.container}>
<Uploadscreen/>
<ListPictures/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
The UploadScreen component works totally fine (this is the one uploading to FB)
And here's my separate component for looping all the images in firebase storage(Which I need help with).
import { firebase } from '../config'
import { View, Image } from 'react-native';
import React, { useState } from 'react';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/compat/storage';
const ListPictures = () => {
const [sampleImage, setSampleImage] = useState();
const getSampleImage = async () => {
const imageRefs = await firebase.storage().ref().child('Front/').listAll();
const urls = await Promise.all(imageRefs.items.map((ref) => ref.getDownloadURL()));
setSampleImage(urls);
}
{ sampleImage && getSampleImage().map(url => (
<View style={{ justifyContent: 'center' }} key={imageRef.id}>
<Image source={{ uri: url }} style={{ width: 350, height: 350 }} />
</View>
))}
}
export default ListPictures;
Any help would be much appreciated!
Try this
import { firebase } from '../config'
import { View, Image } from 'react-native';
import React, { useState, useEffect } from 'react';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/compat/storage';
const ListPictures = () => {
const [sampleImage, setSampleImage] = useState([]);
const getSampleImage = async () => {
const imageRefs = await firebase.storage().ref().child('Front/').listAll();
const urls = await Promise.all(imageRefs.items.map((ref) => ref.getDownloadURL()));
setSampleImage(urls);
}
useEffect(()=>{
getSampleImage()
},[])
{ sampleImage.length!=0 && sampleImage.map(url => (
<View style={{ justifyContent: 'center' }} key={imageRef.id}>
<Image source={{ uri: url }} style={{ width: 350, height: 350 }} />
</View>
))}
}
export default ListPictures;
You shouldn't call asynchronous code while building the UI output as you do here:
{ sampleImage && getSampleImage().map(url => (
What you have will be called on every render, which is likely not what you want.
Instead, put such a call in a useEffect hook with an empty dependencies array:
useEffect(() => {
getSampleImage();
}, []);
This way the call to getSampleImage() runs when the component gets created, rather than on each render.

Share QR React Native

I'm new in react/react native. I'm trying to share a QR Code as image.
Generate QR works, but I want to share it as an image (whatsapp, bluetooth, etc).
import QRCode from 'react-native-qrcode-svg';
let svg = useRef();
//let svg = '';
<QRCode
size={300}
value={`${name}`}
getRef={(c) => (svg = c)}
/>
I tried "get base64 string encode of the qrcode" from official documentation, but I just don't get it
//From Off Doc
getDataURL() {
this.svg.toDataURL(this.callback);
}
callback(dataURL) {
console.log(dataURL);
}
What I tried to do (all my code):
import React, { useRef } from 'react';
import QRCode from 'react-native-qrcode-svg';
const QR = ({ name }: any) => {
let svg = useRef();
const getDataURL = () => {
svg.toDataURL(callback(dataURL));
//console.log(svg);
}
callback(dataURL) {
console.log(dataURL);
}
return (
<>
<QRCode
size={300}
value={`${name}`}
getRef={(c) => (svg = c)}
/>
<Button onPress={getDataURL}
title="Call Funct"
color="#1FAAE2" />
</>
);
get error svg.toDataURL is not a function.
I have been in this for days, I also read another stackover queries with the same problem but solutions in those questions didn't work for me. Thank you in advance guys
Error toDataURL
console.log(svg)
I have changed a couple of things in your code and used it on a expo app where I installed react-native-qrcode-svg and react-native-svg
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, TextInput, Button } from "react-native";
import { useRef } from "react";
import QRCode from "react-native-qrcode-svg";
const QR = ({ name }: any) => {
let svg = useRef<SVG>(null);
const getDataURL = () => {
svg?.toDataURL(callback);
//console.log(svg);
};
function callback(dataURL: string) {
console.log(dataURL);
}
return (
<>
<QRCode size={300} value={`${name}`} getRef={(c) => (svg = c)} />
<Button onPress={getDataURL} title="Call Funct" color="#1FAAE2" />
</>
);
};
export default function App() {
const input = useRef<TextInput>(null);
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
<QR />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
Main changes from your code is defining the callback as a function
// you had
callback(dataURL) {
console.log(dataURL);
}
// but it should be
function callback(dataURL) {
console.log(dataURL);
}
// or
const callback = (dataURL) => {
console.log(dataURL)
}
and doing the call properly on getDataURL
// you had
svg.toDataURL(callback(dataURL));
// but it should be
svg.toDataURL(callback);
After those changes clicking in the button returns the dataURL in the console as expected.
Old answer before question edit:
Your issue seems to be that svg is not defined when you call svg.toDataURL how are you calling the function? If you are doing that on the first render it is possible that the ref is not ready yet.
If you are doing that using a callback in a button in the screen then the issue should be around the code setting the ref.
Can you post your whole component?
My solution with typescript: I needed to add
'// #ts-ignore' because I used Typescript
import React, { useRef } from 'react';
import QRCode from 'react-native-qrcode-svg';
import { TouchableOpacity, Text } from 'react-native';
export const Screen1 = ( ) => {
const svg = useRef();
const getDataURL = () => {
// #ts-ignore
svg.current?.toDataURL(callback);
};
const callback = (dataURL: string) => {
console.log( dataURL );
}
return (
<>
<QRCode
value={ "Some String" }
size={ 250 }
color="black"
backgroundColor="white"
getRef={(c: any) => ( svg.current = c )}
/>
<TouchableOpacity
activeOpacity={ 0.8 }
style={ styles.Button }
onPress={() => getDataURL() }
>
<Text style={ styles.Text }> Press </Text>
</TouchableOpacity>
</>
)
You get the function not found error when you testing it with web, test it with iOS simulator then it will work.

React export component that is not diplayed to PNG

I'm trying to export a chart to an image and I want the chart image to have a custom legend that is not being displayed on screen.
How can I do that?
For now I have tried to export using react-component-export-image but if the component is not displayed the ref is null and It cannot be exported. See component export implementation src-code.
Example of my current code: codesandbox
The only way you can achieve that by manipulating the canvas before render. You can do that by setting the onclone option in html2CanvasOptions.
import { Line } from "react-chartjs-2";
import { exportComponentAsPNG } from "react-component-export-image";
import React, { useRef } from "react";
import { data } from "./data";
const Chart = React.forwardRef((props, ref) => {
return (
<div ref={ref} style={{ maxWidth: "800px" }}>
<Line data={data} height={80} />
<div id="legend" style={{ textAlign: "center", visibility: "hidden" }}>
Legend
</div> {/* Visibility set to hidden using css */}
</div>
);
});
const App = () => {
const componentRef = useRef();
return (
<React.Fragment>
<Chart ref={componentRef} />
<button
style={{ margin: "30px" }}
onClick={() => exportComponentAsPNG(componentRef, {
html2CanvasOptions: {
onclone: (clonedDoc) => {
clonedDoc.getElementById("legend").style.visibility = "visible";
// Visibility set to visible using `onclone` method
},
},
})
}
>
Export As PNG
</button>
</React.Fragment>
);
};
export default App;
https://codesandbox.io/s/export-chart-821kc?file=/src/App.js
This will do the job. Let me know if you need further support.

Material UI CardMedia is not showing images

I'm using CardMedia to display images on the screen but it is not showing it.
I have gone through the similar question on Stack Overflow. There the solution give is to import the image and then use it. But here I'm fetching image url from backend using API call.
I have also tried changng heights but it didn't work.
Can anyone explain what is the issue?
import React from "react";
import axios from "axios";
import Card from "#material-ui/core/Card";
import CardHeader from "#material-ui/core/CardHeader";
import CardMedia from "#material-ui/core/CardMedia";
import CardContent from "#material-ui/core/CardContent";
import CircularProgress from "#material-ui/core/CircularProgress";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: "56.25%",
},
}));
function ProductList(props) {
const [productList, setProductList] = React.useState([]);
const [loading, setLoading] = React.useState(true);
const classes = useStyles();
const url = `https://api.growcify.com/dev/product/list/${props.listId}`;
const getList = () => {
axios.get(url).then((res) => {
console.log(res.data);
setProductList(res.data);
setLoading(false);
});
};
React.useEffect(() => {
getList();
}, []);
return !loading ? (
productList.length > 0 ? (
productList.map((list) => (
<Card className={classes.root}>
<CardContent>{list.name}</CardContent>
{list.photos.map((img) => {
img !== null && (
<Card className={classes.root}>
{console.log(img)}
<CardMedia
image={img}
component="img"
title="Some title"
className={classes.media}
/>
</Card>
);
})}
</Card>
))
) : (
<h2>No Data Available </h2>
)
) : (
<CircularProgress />
);
}
export default ProductList;
In the provided Screenshot, You can see in the console that I'm getting image url but image is not showing there.
Remove height: 0, from media style
image={"http://localhost:3000/yourPath/"+this.state.your-data.your-variable name}
Dont forget to padding top
Tell me if it works :D

Expo React Native, How to pick default local images or user image obtained from expo image picker

I have a form that a user can select a default local image or an image from the user's photo library
Here is an expo snack use android the images can be found in the phone menu in photos
I want to save either the default local image or user's image to the form and to redux, currently able to save default images picked to form and redux.
This is what currently works.
I have a component that gets a selected local image and returns an image path witch is a number. That local image gets saved in form and in redux. currently, the user can change the local image in the form.
ImgSelector Component:
import React, { useState } from "react";
import { List, Selector, View, SelectedImg } from "./styles";
import { FlatList } from "react-native";
import { defaultImages } from "../../data/defaultImages";
const FlatlistItem = ({ image, setImg }) => {
return (
<Selector onPress={() => setImg(image)}>
<View>
<SelectedImg source={image} />
</View>
</Selector>
);
};
const ImgSelector = ({ setImg }) => {
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => (
<FlatlistItem setImg={setImg} image={item.image} />
);
return (
<View>
<FlatList
horizontal
data={defaultImages}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={selectedId}
/>
</View>
);
};
export default ImgSelector;
Default local images are stored like this and the path is the index which is a number this part works fine.
export const defaultImages = [
{
id: “2”,
image: require("../assets/images/singlepane.png"),
}
]
I have an imagePicker component that asks for permissions and returns a uri string that looks like this:
file:/data/data/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FExpoWcPro-a828b17b-dcd7-4a04-93ca-657c8e4e511d/ImagePicker/6106d73f-c886-457d-abe9-1f1232a0d398.jpg
My form component where images are picked and saved:
import React, { useState } from "react";
import { Image } from "react-native";
const CounterForm = ({ navigation, ...props }) => {
// This is current state for default images that works
const [imgUrl, setImgUrl] = useState(props.imgUrl || defaultImage);
const [userImgUri, setUserImgUri] = useState(null);
// This gets the local image from a componnet
const handleEditImg = (newImgUrl) => {
setImgUrl(newImgUrl);
};
// This gets image uri from expo image picker
const handelUserImg = (userUri) => {
setUserImgUri(userUri);
};
// This sends data to a redux action to save
const handleSubmit = () => {
props.onFormSubmit({
id: props.id,
imgUrl,
});
setImgUrl(defaultImage);
};
return (
<FormWrapper>
<Row>
<FormButton onPress={() => handleSubmit()}>
<StyledText title="Save" color={COLORS.appBlue} />
</FormButton>
</Row>
<TopContent>
{/* I tried this to get user image and displays in form */}
<Image
source={{ uri: userImgUri }}
style={{ width: 100, height: 100 }}
/>
{/* This current implementation gets local images
<Image
source={imgUrl}
style={{ width: 100, height: 100 }}
/> */}
{/* I tried this only gets local images
{imgUrl ? (
<Image source={imgUrl} style={{ width: 100, height: 100 }} />
) : (
<Image
source={{ uri: userImgUri }}
style={{ width: 100, height: 100 }}
/>
)} */}
</TopContent>
<Row>
<ImagePicker getUserImg={handelUserImg} />
</Row>
<View>
<ImgSelector setImg={handleEditImg} />
</View>
</FormWrapper>
);
};
export default CounterForm;
if you use the last sdk version of Expo (40) and the right package expo-image-picker you need to follow this instructions.
First you need to ask for permissions :
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
And then call method to select image from library :
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
So you got image uri by accessing result.uri, you need to save this value (e.g in user store) and display it by selecting your store or default value if there is not stored value :
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Pick an image from camera roll" onPress={pickImage} />
/** imgUrl = stored image uri, defaultImages[0].image = default image uri */
<Image source={imgUrl ? { uri: imgUrl } : defaultImages[0].image} />
</View>
I found the answer it's updated in expo snack
import React, { useState } from "react";
import { List, Selector, View, SelectedImg } from "./styles";
import { FlatList } from "react-native";
import { defaultImages } from "../data";
const FlatlistItem = ({ image, setImg }) => {
return (
<Selector onPress={() => setImg(image)}>
<View>
<SelectedImg source={{uri: image}} />
</View>
</Selector>
);
};
const ImgSelector = ({ setImg }) => {
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => {
return (
<FlatlistItem setImg={setImg} image={item} />
)
}
return (
<View>
<FlatList
horizontal
data={defaultImages}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={selectedId}
/>
</View>
);
};
export default ImgSelector;
Form
import React, { useState } from "react";
import {Asset} from 'expo-asset';
import StyledText from "../UiComponents/StyledText";
import { TouchableWithoutFeedback, Keyboard } from "react-native";
import {
FormWrapper,
TextInputWrapper,
TopContent,
NumberWrapper,
Row,
FormButton,
View,
} from "./styles";
import StyledInput from "../UiComponents/StyledInput";
const defaultImage = Asset.fromModule(require('../assets/komloy.jpg')).uri
import WindowSelector from "../ImgSelector";
import StyledButton from "../UiComponents/StyledButton";
import ImagePicker from "../components/imagePicker";
import { Image } from "react-native";
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
const CounterForm = ({ navigation, ...props }) => {
const [imgUrl, setImgUrl] = useState(props.imgUrl || defaultImage);
const handleEditImg = (newImgUrl) => {
setImgUrl(newImgUrl);
};
const handelUserImg = (userUri) => {
setImgUrl(userUri);
};
const handleSubmit = () => {
props.onFormSubmit({
id: props.id,
imgUrl
});
setImgUrl(defaultImage);
};
return (
<DismissKeyboard>
<FormWrapper>
<TopContent>
<Image
source={{uri: imgUrl}}
style={{ width: 100, height: 100 }}
/>
</TopContent>
<Row>
<StyledText title="Select a image" />
<ImagePicker getUserImg={handelUserImg} />
</Row>
<View>
<WindowSelector setImg={handleEditImg} />
</View>
</FormWrapper>
</DismissKeyboard>
);
};
export default CounterForm;
Data
import {Asset} from 'expo-asset';
const imageURI = Asset.fromModule(require('./assets/islands.jpg')).uri
const imageURI2 = Asset.fromModule(require('./assets/maeYai.jpg')).uri
export const defaultImages = [
imageURI, imageURI2
]

Categories