React - How to show skeleton placeholders until Array map function ended - javascript

I have a country list component that contains country phone codes, country names and their flags using map() function so it takes a bit long to load. I need to get the information if map() function ended or still working then use it for showing then hiding placeholders. How could I achieve that?
I couldn't find proper solutions on Internet or couldn't use them. Like when using Promise(all) in a React Component, I've been having hardness to figure out how syntax should be.
<CountryList /> component:
// Packages I used for countries
import { getCountries, getCountryCallingCode } from "react-phone-number-input"
import countryNames from "react-phone-number-input/locale/en.json"
import ReactCountryFlag from "react-country-flag"
// The array comes from package
const countries = getCountries()
<CountryList>
{countries.map((country) => (
<CountryItem key={country} value={country}>
<ReactCountryFlag countryCode={country} svg />
<span>
{countryNames[country]}
<span>+{getCountryCallingCode(country)}</span>
</span>
</CountryItem>
))}
</CountryList>
<CountryItemSkeleton /> component:
// The package I used for skeleton placeholder
import ContentLoader from "react-content-loader"
<CountryItemSkeleton>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
</CountryItemSkeleton>

Everything here is synchronous so you cannot wait for or monitor the map() progress.
What you can try though is loading the country list in an effect hook so that it's populated after your component is mounted. On the initial render you can use your skeleton component
const [countries, setCountries] = useState([]);
// run once on mount
useEffect(() => {
setCountries(getCountries());
}, []);
// or even with a small delay
useEffect(() => {
const timer = setTimeout(setCountries, 200, getCountries());
return () => {
clearTimeout(timerId);
};
}, []);
return countries.length === 0 ? (
<CountryItemSkeleton />
) : (
<CountryList>
{countries.map((country) => (
<CountryItem key={country} value={country}>
{/* etc */}
</CountryItem>
))}
</CountryList>
);

Related

Both click() and dispatchEvent does not trigger automatic click in reactjs

I have a react component that has an SVG image. I have divided the SVG into multiple react box. I have query selector which selects all the react box and JS click event to auto click that react.
I tried working with both click and dispatch event. But none of them works in my scenario.
Below is the section of the code I am working on.
componentDidMount() {
var element = document.querySelectorAll("square");
for(var i = 0; i<element.length; i++) {
element[i].dispatchEvent(new Event('click'));
}
}
render(){
return (
<React.Fragment>
<div className="col-12">
<svg viewBox="0 0 100 100">
<image xlinkHref={imageFile} height="100%" width="100%" />
<g><rect className="square" x="10" y="10" width="20" height="10" fillOpacity=".2" onClick={() =>console.log("clicked")}></rect> </g>
<g><rect className="square" x="30" y="10" width="20" height="10" fillOpacity=".4" onClick={() =>console.log("clicked")}></rect> </g>
</svg>
</div>
</React.Fragment>
)
}
I also tried using the click() function and did not work for SVG images and also is there a way we could automate a click in each square every 10 seconds?
You forgot a . in the query selector so the node list was actually empty.
If you want to automate a click in each square every 10 seconds, this code does the trick:
const elements = document.querySelectorAll(".square");
const intervalsIdentifiers = Array.from(elements).map(x => setInterval(() => x.dispatchEvent(new Event('click')), 10000));
The dispatchEvent method is indeed the only way, because the rect element doesn't have a click method (only HTML elements do, not SVG elements) as demonstrated below:
console.log('click' in SVGRectElement.prototype); // false
console.log(HTMLElement.prototype.hasOwnProperty('click')); // true
console.log(HTMLButtonElement.prototype instanceof HTMLElement); // true (a button has the click method)
console.log(SVGRectElement.prototype instanceof HTMLElement); // false
The full working code (native JavaScript but should work as well with React in the componentDidMount hook):
const elements = document.querySelectorAll(".square");
const intervalsIdentifiers = Array.from(elements).map(x => setInterval(() => x.dispatchEvent(new Event('click')), 10000));
<div className="col-12">
<svg viewBox="0 0 100 100">
<image xlink:Href="https://img-19.ccm2.net/8vUCl8TXZfwTt7zAOkBkuDRHiT8=/1240x/smart/b829396acc244fd484c5ddcdcb2b08f3/ccmcms-commentcamarche/20494859.jpg" height="100%" width="100%" />
<g><rect class="square" x="10" y="10" width="20" height="10" fillOpacity=".2" onclick="console.log('clicked')"></rect> </g>
<g><rect class="square" x="30" y="10" width="20" height="10" fillOpacity=".4" onclick="console.log('clicked')"></rect> </g>
</svg>
</div>

Svg issues on Safari

I am using svg icons for expanding and collapsing a component. They are rendering correctly as you can see in the following image:
but when I expand a component and perform an action the svgs begin to look like this:
I have verified there is absolutely no change in the svg component and they return to the correct view after I expand another component. This issue is occuring at multiple locations where I am using svg icons. I am using React and the svg icons are loaded as components. This only occurs on Safari and no other browser
Edit
The code for the svg is :
export const CollapseIcon = () => (<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
width="24"
height="24"
viewBox="0 0 24 24">
<defs>
<path
id="gt4gdtq39a"
d="M7.146 9.146c.174-.173.443-.192.638-.057l.07.057L12 13.293l4.146-4.147c.174-.173.443-.192.638-.057l.07.057c.173.174.192.443.057.638l-.057.07-4.5 4.5c-.174.173-.443.192-.638.057l-.07-.057-4.5-4.5c-.195-.196-.195-.512 0-.708z"
/>
</defs>
<g fill="none" fillRule="evenodd">
<g>
<g transform="translate(-956 -290) translate(956 290)">
<mask id="reyuf8n5tb" fill="#fff">
<use xlinkHref="#gt4gdtq39a" />
</mask>
<use fill="#000" fillRule="nonzero" xlinkHref="#gt4gdtq39a" />
<g fill="#F7274A" mask="url(#reyuf8n5tb)">
<path d="M0 0H24V24H0z" />
</g>
</g>
</g>
</g>
);
and I am using it as a simple component like:
{expanded ? <CollapseIcon /> : <ExpandIcon />}

How do I use SVGs for background images on buttons in React

First timer on stack overflow so I'll try my best.
I'm trying to dynamically add SVGs as background images for my buttons.
Created react app using create-react-app.
I have 3~ files in question: poland.svg, Flag.jsx and exampleComponent.jsx
exampleComponent.jsx
import React from 'react';
import Flag from './Flag.jsx';
const exampleComponent = (props) => {
const backgroundImage = {
backgroundImage: `url(${Flag(props.nation)})`
}
return(
<button style={backgroundImage}>
<div />
</button>
)
}
export default exampleComponent;
Flag.jsx
import Poland from './poland.svg';
import US from './us.svg';
const Flag = (nation) => {
let path = "";
if (nation === "Poland") path = Poland;
else if (nation === "US") path = US;
return path;
}
export default Flag;
poland.svg
<svg
height="100%"
width="100%"
>
<defs />
<rect fill="#ffffff" width="100%" height="50%" />
<rect transform="translate(0, 50px)" fill="#ff0000" width="100%" height="50%" />
</svg>
I'm getting the file path /static/media/poland.49b43928.svg
When I inspect the element in chrome the correct file path is shown but the SVG isn't being loaded!
IM STILL A NOOB! so please be harsh! ;D
Update! So the file was being sent in XML format.. I wish I knew more to explain the details but all I did to fix this was add:
xmlns="http://www.w3.org/2000/svg"
to the svg tags like so:
<svg
height="100%"
width="100%"
xmlns="http://www.w3.org/2000/svg"
>
<defs />
<rect fill="#ffffff" width="100%" height="50%" />
<rect transform="translate(0, 50px)" fill="#ff0000" width="100%" height="50%" />
</svg>
If the svg files are similar, there may be a problem with matching the
<use xlink ID:href="#xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"/>,
where xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxx is the ID, it must be unique for each file.
See the link, it may help
https://github.com/SilverFox70/svg-react-loader

Cannot pass multiple attributes of an elements to a java script function

I am trying to pass the id and name attributes from below elements to handle Click event but only the id is being passed. When debugging name shows "undefined". Did I miss anything
function App() {
const [id, setId] = React.useState('')
const [name, setName] = React.useState('')
const handleClick = event => {
debugger
setName(event.target.name)
setId(event.target.id)
}
return (
<form>
<svg width="800" height="250">
<rect onClick={handleClick} id="0" name="Rectangle" x="10" y="10" width="150" height="150" fill="green" />
<circle onClick={handleClick} id="1" name="Circle" cx="300" cy="90" r="75" fill="red" />
<polygon onClick={handleClick} id="2" name="Triangle" points="500,10 600,160 400,160" style={{ fill: "blue" }} />
</svg>
<Display id={id} name={name} />
</form>
)
}
Debugging screen shot below
const handleClick = event => {
// debugger
setName(event.target.id);
setId(event.target.getAttribute("name"));
};
demo
https://codesandbox.io/s/frosty-breeze-emiwc?file=/src/App.js
Please try this:
<rect onClick={(e) => {
this.clickMe(e, {id: "0", name: "Rectangle"})
}}>Click Me</rect>
The function body
function clickMe(event, attribute){
console.log(attribute.id);
console.log(attribute.name);
}

How to mask user image in SVG hexagon shape on react native

I am struggling with hexagon shape on react native can anyone have some idea about how does it work using svg in react native or any alternate way?
creating shapes using js
image cutout of hexagon
masking image[enter image description here][1]
I'm trying this below image.
https://i.stack.imgur.com/MLDFl.jpg
This is My code:
render() {
return (
<Svg
height="300"
width="300"
viewBox="0 0 860 860"
>
<Defs>
<ClipPath id="clip">
<Polygon
strokeWidth="2"
stroke="#979797"
strokeDasharray='8,8'
strokeLinecap='butt'
fill="rgba(0, 0, 0, 0.5)"
points="258.5,223.999 130.5,298 2.5,224 2.5,76 130.5,2 258.5,76 " />
</ClipPath>
</Defs>
<Image
x="0%"
y="0%"
width="100%"
height="100%"
preserveAspectRatio="xMidYMid slice"
opacity="0.5"
href={require('./assets/Image.jpg')}
clipPath="url(#clip)"
/>
</Svg>
);
}
This kind of image can be created with my react-native-image-filter-kit module:
import { Image } from 'react-native'
import { DstATopComposition } from 'react-native-image-filter-kit'
const style = { width: 320, height: 320 }
const masked = (
<DstATopComposition
dstImage={
<Image
style={style}
source={{ uri: 'https://i.stack.imgur.com/MLDFl.jpg' }}
/>
}
srcImage={
<Image
style={style}
source={{ uri: 'http://www.myiconfinder.com/uploads/iconsets/256-256-53d5151ca4f467ed9951f85024881c85.png' }}
/>
}
/>
)
Note that shape generation is not supported currently, so you need to use another image for masking.

Categories

Resources