How to render SVG images inside a div - javascript

I'm new to react and i hope someone can help me with this. I've searched everywhere for a solution to my problem with no luck.
Basically i want to render an array of SVG images inside a div as a backgroundImage: url().
I've managed to render my array with math.random but i want the SVG images to render in same order as in the array.
This is my code so far:
import './ListView.css';
import Green from '../Assets/ListCard/Green.svg';
import Brown from '../Assets/ListCard/Brown.svg';
import Orange from '../Assets/ListCard/Orange.svg';
import Mail from '../Assets/Icons/Mail.svg'
import Phone from '../Assets/Icons/Phone.svg'
function ListView({ userData}) {
const cardImages = [Green, Brown, Orange]; /// Array
const renderList = cardImages.map(function(image) { /// Tried to map through the array with -
return image; /// no luck
})
/// This Math.radom method works, but not the solution i want
const randomItem = cardImages[Math.floor(Math.random()*cardImages.length)];
return ( /// Below inside the div is where i want to render the images.
<div className="list-card" style={{backgroundImage: `url(${renderList})`}}>
<div className="list-card-wrapper">
<div className="list-user-image"><img src={userData.picture.medium} alt=""/></div>
<div className="list-user-info">
<div className="list-user-name">{userData.name.first} {userData.name.last}</div>
<div className="list-user-location">{userData.location.city}</div>
</div>
<div className="list-user-contact">
<img height={19} src={Mail} alt="svg"/>
<img height={19} src={Phone} alt="svg"/>
</div>
</div>
</div>
)
}
export default ListView```

you will need import image and bind it like below:
import logo from './logo.svg';
function App() {
return (
<div className="App">
<img src={logo} className="App-logo" alt="logo" />
</div>
);
}
export default App;

This is what you might be looking for:
import "./styles.css";
export default function App() {
const items = [
{ name: "first" },
{ name: "second" },
{ name: "third" },
{ name: "fourth" },
{ name: "fifth" },
{ name: "sixth" }
];
const colorArray = ["green", "brown", "orange"];
return (
<div className="App">
{items.map((item, index) => {
const classColorIndex = index % 3;
return (
<div
className={`list-card ${colorArray[classColorIndex]}`}
key={index}
>
<p>{item.name}</p>
</div>
);
})}
</div>
);
}
The main concept behind this is, that you have to focus on the index of the item and check if it the first, second, or third item (I am considering it 3 because you have 3 colors in the array). Now, according to index number, you need to add a class to that div, and using CSS, you could provide background to each div according to that array.
In this sample, I have used plain background color, but I have commented how you could use svg as well. on APP.css, and here is the css
.App {
font-family: sans-serif;
text-align: center;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.list-card {
width: 50px;
height: 50px;
display: flex;
justify-content: center;
flex-basis: 50%;
}
.list-card.green {
background: green;
/* background:url('../../Green.svg'); */
}
.list-card.brown {
background: brown;
}
.list-card.orange {
background: orange;
}
and here is the sandbox link:
https://codesandbox.io/s/stack-overflos-sample-z0yxyk?file=/src/App.js
On this example, you can see background is assigned, exactly to the array.

Related

React hooks - set state of Parent from child via function

guys I am just learning React and I decide to do try to build Hero Database and I encounter a problem.
When I click on any of Heroes, Bio state and Display state updates with data about the hero and modal window pop up with more information about him. But I don't know how to close it. I have Modal as a separate component and when I am trying calling the function (updateDisplay) from child component. which should set State of Display to False it just doesn't work :/
Heroes.js
import React, { useState } from "react";
import Hero from "./Hero";
import styled from "styled-components";
function Heroes(props) {
const [Bio, setBio] = useState([]);
const [Display, setDisplay] = useState(false);
const SingleHeroCont = styled.div`
display: flex;
flex-direction: column;
margin-top: 10px;
padding: 10px;
align-items: center;
`;
const content = props.data.map((Hero) => (
<SingleHeroCont
onClick={() => {
setBio(Hero);
setDisplay(true);
}}
key={Hero.id}
>
<h1>{Hero.name}</h1>
<img src={Hero.images.sm} alt="Sorry guys"></img>
</SingleHeroCont>
));
const updateDisplay = () => {
setDisplay(false);
};
return (
<div className="heroes_cont">
<Hero updateDisplay={updateDisplay} Display={Display} BioData={Bio} />
{content}
</div>
);
}
export default Heroes;
Hero.js
import React from "react";
import styled from "styled-components";
function Hero({ Display, updateDisplay, BioData }) {
const HeroAbsolute = styled.div`
display: ${(props) => (props.showBio ? "block" : "none")};
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 255, 255, 0.5);
`;
return (
<HeroAbsolute showBio={Display}>
<div className="hero_bio_cont">
<h1>{BioData.name}</h1>
<button onClick={() => updateDisplay}>Close</button>
<div className="hero_bio_appearance">
<div>
<img></img>
<div>
<h2>{BioData.powerstats?.power}</h2>
<h2></h2>
<h2></h2>
</div>
</div>
</div>
</div>
</HeroAbsolute>
);
}
export default Hero;
<button onClick={() => updateDisplay}>Close</button>
As I see, the above code is not working to call updateDisplay function.
Correct usage would be
<button onClick={() => updateDisplay()}>Close</button>
Or
<button onClick={updateDisplay}>Close</button>
Please refer to the arrow function tutorial for the second case.

Place 2 elements per div side-by-side in React

I have an array like this:
const arr = [1,2,3,4,5,6,7,8,9,10]
And I want to place them as 2 per one line in two dimensional divs. Let me illustrate what im trying to say:
This is main React element:
render() {
return <div className="base">{...}</div>
}
Expected Result:
render() {
return <div className="base">
<div className="container">
<div className="left">
<span>1</span>
<span>2</span>
</div>
<div className="right">
<span>3</div>
<span>4</div>
</div>
</div>
<div className="container">
<div className="left">
<span>5</span>
<span>6</span>
</div>
<div className="right">
<span>7</div>
<span>8</div>
</div>
</div>
<div className="container">
<div className="left">
<span>9</span>
{/* no 10th element because 9 is the last. */}
</div>
{/* no right div because no more elements. */}
</div>
</div>
}
If this was a typical odd even situation, I would do i % 2 here. However, how am i going to close div tag on odd or even? But it is a bit more complicated than that. Is there any way to achieve this in React? I'm using TypeScript by the way and latest ReactJS.
In order to render more advanced loops in react, you need to get used to chunking your arrays. you can simply chunk the array twice using the following function, then you can map this array recursively to render your desired output:
function chunk_array(arr,chunkSize=2) {
const result=[];
for(let i=0;i<arr.length;i+=chunkSize) {
result.push(arr.slice(i,i+chunkSize));
}
return result;
}
**NOTE: I made a JS fiddle so you can visualize how this array changes to become the shape we need to render your desired html output ** JS FIDDLE
now you can utilize this in render to accomplish what you want.
import React from 'react';
function chunk_array(arr,chunkSize=2) {
const result=[];
for(let i=0;i<arr.length;i+=chunkSize) {
result.push(arr.slice(i,i+chunkSize));
}
return result;
}
const arr = [1,2,3,4,5,6,7,8,9,10];
const chunked = chunk_array(chunk_array(arr));// we chunk array twice to get desired structure.
class Example extends Component {
render() {
return (
<div className="container">
{chunked.map((container,i)=>(
<div className="base" key={i}>
{container.map((row,i2)=>(
<div key={i2} className={(i2===0?"left":"right")}>
{row.map((item,i3)=><span key={i3}>{item}</span>)}
</div>))}
</div>))}
</div>
)
}
}
This can be done in some ways but here is a sample: https://codesandbox.io/s/distracted-joliot-lkdxq
import React from "react";
import "./styles.css";
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const Result = () => {
return (arr.map(item => {
return (
<div key={item} className="box">
{item}
</div>
);
}));
};
export default function App() {
return (
<div className="App">
<Result />
</div>
);
}
Here is the css:
.App {
display: grid;
grid-template-columns: 50px 50px;
grid-gap: 10px;
}
.box {
display: flex;
border: 1px black solid;
width: 50px;
height: 50px;
align-items: center;
justify-content: center;
}
I think this is the answer you are looking for:
https://codesandbox.io/s/goofy-snowflake-tdzjn?file=/src/App.js
import React from "react";
import "./styles.css";
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const Result = () => {
return arr.map((item, index) => {
return (
index % 2 === 0 && (
<div key={item} className="box">
<span>{arr[index]}</span>
<span>{arr[index + 1]}</span>
</div>
)
);
});
};
export default function App() {
return (
<div className="App">
<Result />
</div>
);
}
Here is the css:
.App {
display: grid;
grid-template-columns: 50px 50px;
grid-gap: 10px;
}
.box {
display: flex;
border: 1px black solid;
width: 50px;
height: 50px;
align-items: center;
justify-content: center;
}
.box span {
margin: 0 5px;
}
You could use bootstrap to do this. Put the everything inside a div className="row" and then have each of the items have className="col-6". Bootstrap cuts every row into 12 columns, so giving each element 6 of those columns will cause them to be 2 on a line as you want. You'll need to npm install bootstrap and include the appropriate script tags in your application. Take a look here, https://getbootstrap.com/docs/3.3/getting-started/. Let me know if this helps!

Styled component: Herencia

I am writing a React application with styled components, creating a library of reusable components for my application, but I encounter the problem of inheritance between sister components when trying to give a property to a label that is next to my input when the input is required, but it does not work. I have tried with:
// Form.js
import { StyledLabel, StyledInput } from './styles.js'
<StyledLabel>Mi Label 1</StyledLabel>
<StyledInput required/>
// ./styles.js
import styled from 'styled-components'
export const StyledInput = styled.input`
border: 1px #dddd solid;
`
export const StyledLabel = styled.label`
font-size: 10px;
${StyledInput}['required'] + & {
&::after {
content: '*'
}
}
`
The result only returns the form without the *
Does anyone know how I can detect from Styled Components when an input has the required HTML attribute, and show the *
Pseudo-selectors in styled-components work just like they do in CSS. (or rather, Sass).
So you can do what you want this way:
const Wrapper = styled.div`
label {
&:after {
content: "${p => p.required && "*"}";
color: red;
}
}`;
const Form = () => {
return (
<Wrapper required>
<label>Mi Label 1</label>
<input />
</Wrapper>
);
};
But if you want don't want to pass props of the input element to its parent you can
do it this way:
const Wrapper = styled.div`
display: flex;
flex-direction: row-reverse;
align-items: center;
`;
const Example = styled.input`
+ label {
&:after {
content: "${p => p.required && "*"}";
color: red;
}
}
`;
const Form = () => {
return (
<Wrapper required>
<Example />
<label>My Label 1</label>
</Wrapper>
);
};
more info in resources:
Before and After pseudo classes used with styled-components
https://github.com/styled-components/styled-components/issues/388
https://github.com/styled-components/styled-components/issues/74

React.js Popup modal for shopping cart

I am currently working on a shopping cart and I am trying to figure out how to have the modal appear once I click on the shopping cart icon. I have looked at the documentation for the semantic-ui for modals but it is vague as to how to get the modal to appear when clicking on something. I am using the semantic-ui class="ui modal" for the modal.
I was thinking of putting an onClick on the icon but was still confused as to how to go from there. Currently, I have the icon in another component and the shopping cart in another separate component. I want the items to appear inside of the pop-up modal which should be the shopping cart.
import React from 'react'
import { Icon } from 'semantic-ui-react';
const ShoppingCartIcon = () => {
return(
<Icon.Group size='big' className="shopping_cart_icon">
<Icon link name='shopping cart'/>
<Icon corner='top right'/>
</Icon.Group>
)
}
export default ShoppingCartIcon;
import React from 'react'
import Shirt from './Shirt';
class ShoppingCart extends React.Component {
render() {
const listShirts = this.props.shirts.map(shirt => {
return <Shirt key={shirt.id} {...shirt}/>
})
return(
<div className="ui modal">
<div className="content">
{listShirts}
</div>
</div>
)
}
}
export default ShoppingCart;
Currently, I do not have the functionality for adding items to the cart working yet. I just want to focus on getting the modal to show up once I click on the shopping cart icon
as far as I see, you are not using neither redux nor context api. you are passing props with props drilling.
so this is how you should organize your code step by step.
we render cartIcon component in the header.js. here is a classic header
Header.js
import CartDropdown from "../cart-dropdown/cart-dropdown.component";
class Header extends React.Component {
constructor(props) {
super(props);
state = { hidden: true, cartItems:[]};
}
toggleHidden() {
this.setState(() => ({ hidden: !this.state.hidden }));
}
render() {
return (
<div className="header">
<Link className="logo-container" to="/">
<Logo className="logo" />
</Link>
<div className="options">
<Link className="option" to="/shop">
SHOP
</Link>
<Link to="/contact" className="option">
CONTACT
</Link>
{/* <Link></Link> */}
<CartIcon />
</div>
{hidden ? null : (
<CartDropdown
toggle={this.toggleHidden}
cartItems={this.state.cartItems}
></CartDropdown>
)}
</div>
);
}
}
you said you have not set the addItem functionality yet. as you add items to the cartItems array you will display them in the cart.
now we need to set up the cartDropdown component.
const CartDropdown = ({ cartItems, toggleHidden }) => (
<div className="cart-dropdown">
<div className="cart-items">
{cartItems.length ? (
cartItems.map(item => <CartItem key={item.id} item={item} />)
) : (
<span className="empty-message"> Your cart is empty </span>
)}
</div>
<CustomButton
onClick={() => {
toggleHidden();
}}
>
GO TO CHECKOUT
</CustomButton>
</div>
);
here we need to add css for cartDropdown. I do not how you are dealing with your css. prop-types or scss but here is the css code so you can apply to your project.
css for cartDropdown component
.cart-dropdown {
position: absolute;
width: 240px;
height: 340px;
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid black;
background-color: white;
top: 80px;
right: 0;
z-index: 5;
.cart-items {
height: 240px;
display: flex;
flex-direction: column;
overflow: scroll;
}
.empty-message {
font-size: 18px;
margin: 50px auto;
}
button {
margin-top: auto;
}
}

How to create virtual scrolling for images using React js

Whats my requirement: i have some images in my external folder and i need to import to component and display it and also have to use Virtual Scroll here i have to display 1 row in div and in that 1 row have to show 5-6 images
What i did : i consumed images using context from external folder and showed images in 1 rows in div and 5-6 images but i am facing issue unable to set it to Virtual scrolling
as i checked react-virtualized & react-window plugin but i am not sure how my data is used in that format
After using the react-tiny-virtual-list images are getting stacked
below is my code
class App extends React.Component{
state={
Response:[],
}
importAll(r) {
return r.keys().map(r);
}
componentWillMount() {
let data = this.importAll(require.context('./imageFolder/', false, /\.(png|jpe?g|svg)$/));
this.setState({ Response:data})
}
render(){
return(
<div className="container" id="imagecontainer">
<div className="viewport">
{this.state.Response.map((image, index) => <img key={index} src={image} alt="info"></img> )} }
</div>
</div>
)
}
.container {
padding: 0% 6%;
height: 400px;
}
.viewport {
height: -webkit-fill-available;
width: 100%;
border: 1px solid black;
overflow: scroll;
}
img {
height: 250px;
width: 150px;
padding: 35px;
}
After implementing React-tiny-list
<div id="container">
<div id="viewport">
<VirtualList
height='400px'
width='100%'
itemCount={this.state.items.length}
itemSize={20} // Also supports variable heights (array or function getter)
style={{padding:'20px'}}
renderItem={({index, style}) =>
<div key={index} style={style}>
<img key={index} src={this.state.items[index]} alt="info"></img>
</div>
}
/>
</div>
</div>
you can also use the https://github.com/bvaughn/react-virtualized plugin in this if you want to display this as table you can choose list or you can choose grid also .For you requirement i recommend using Masonry from 'react-virtualized';
below is the sample for displaying
import React from 'react';
import {
CellMeasurer,
CellMeasurerCache,
createMasonryCellPositioner,
Masonry
} from 'react-virtualized';
import 'react-virtualized/styles.css';
var images = [];
const columnWidth = 250;
const defaultHeight = 260;
const defaultWidth = columnWidth;
const cache = new CellMeasurerCache({
defaultHeight,
defaultWidth,
fixedWidth: true
})
// Our masonry layout will use 3 columns with a 10px gutter between
const cellPositioner = createMasonryCellPositioner({
cellMeasurerCache: cache,
columnCount: 4,
columnWidth,
spacer: 27
})
function cellRenderer ({ index, key, parent, style }) {
const datum = images[index]
const height = columnWidth || defaultHeight ;
return (
<CellMeasurer
cache={cache}
index={index}
key={key}
parent={parent}
>
<div style={style}>
<img
src={datum}
style={{
height: height,
width: columnWidth,
display: "block"
}}
alt="info"
/>
</div>
</CellMeasurer>
)
}
class Grid extends React.Component{
importAll(r) {
return r.keys().map(r);
}
componentWillMount() {
images = this.importAll(require.context('../imageFolder/', false, /\.(png|jpe?g|svg)$/));
}
render(){
return(
<div id="container">
<div id="viewport">
<Masonry
cellCount={images.length}
cellMeasurerCache={cache}
cellPositioner={cellPositioner}
cellRenderer={cellRenderer}
height={400}
width={1320}
/>
</div>
</div>
)
}
}
export default Grid;
I hope this will resolve your issue
If you're having trouble implementing the virtual scroll, note that the order of the imports is important when doing this, so pay heed to this - it could be contributing to your issue. (An aside: There is an npm plugin for implementing a virtual list.)
An overview of the import order for virtual scroll is:
import * as React from 'react';
import Paper from '#material-ui/core/Paper';
import {
Grid,
VirtualTable,
TableHeaderRow,
} [from material ui];
import {
your-components
} from 'your-path';
(above is non-specific, just a rough guide to the order)
You could also use a ScrollView if you are unable to implement a "Virtual scroll".
The following style will give you a horizontal scroll (as opposed to the default vertical), to enable you to display your images in a horizontally-scrollable row
<ScrollView horizontal={true}>
Hope this helps

Categories

Resources