Using spread operator in Styled-Components - javascript

I'm new to React and React-Spring and practicing how to use it.
There's really basic code from React-Spring document, and I want to convert it using styled-components.
I converted code to styled-components but don't know how to change ...springs in styled-components.
Can I know how to apply it with using styled-components??
document code: codesandbox
import '/index.css'
import { useSpring, animated } from '#react-spring/web'
export default function MyComponent() {
const springs = useSpring({
from: { x: 0 },
to: { x: 100 },
})
return (
<animated.div
style={{
width: 80,
height: 80,
background: '#ff6d6d',
borderRadius: 8,
// don't know how to conver this part
...springs,
}}
/>
)
}
my code: codesandbox
import { useSpring, animated } from "#react-spring/web";
import styled from "styled-components";
export default function App() {
const springs = useSpring({
from: { x: 0 },
to: { x: 100 }
});
return (
<Spring>
<animated.div className="box">hi</animated.div>
</Spring>
);
}
const Spring = styled.div`
border: 3px solid black;
.box {
width: 80px;
height: 80px;
background: #ff6d6d;
border-radius: 8px;
//this part doesn't work
...springs;
}
`;

Having styled components or not doesn't affect your code: you should still spread the springs object directly into <animated.div>.
return (
<Spring>
<animated.div className="box" style={{ ...springs }} />
</Spring>
);
If you truly want to offload all the styling to styled-components, you can create a new styled component that uses animated.div internally, i.e.:
const SpringBox = styled(animated.div)`
width: 80px;
height: 80px;
background: #ff6d6d;
border-radius: 8px;
`;
Then you can update your template as such: but note that you are still spreading the springs in the JSX template and not passing it via styled components:
return (
<Spring>
<SpringBox style={{ ...springs }} />
</Spring>
);

Related

How to pass two state variables into the same React useState? - Array & Integer

Working on an e-commerce store project where I have a Slider component.
I am fetching my own JSON data from a localhost server & mapping over the array for each slide.
My goal is to find a way to use the same useState() to render the items onto the page & click a button to move to the next slide.
I have tried to do something like useState([], 0)
One for my array & another one to change index on button click however this did not work lol...
The array is of course for the data to be displayed however the tricky part for me is figuring out a way to move to the next page.
I am trying to use transform:translateX in my Wrapper styled component and attempting to pass props in so I can change the slide to the next slide and still render the data on the page.
How can I go about using state in this way described above based on my code?
*** Before reading the code snippets, my current code shows that I have tried creating two states, and passing the second state with my integer into my fetch request, no errors pop up but it doesn't work obviously as it doesn't have an array of items to index through.
In the code snippet I have included the code for the entire slider & also the information inside my data.json file.
import {useState, useEffect} from 'react';
import { ArrowLeftOutlined, ArrowRightOutlined } from "#material-ui/icons";
import styled from "styled-components";
const Container = styled.div`
width: 100%;
height: 95vh;
display: flex;
// background-color: #b3f0ff;
position: relative;
overflow: hidden;s
`;
const Arrow = styled.div`
width: 50px;
height: 50px;
background-color: #e6ffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: ${props => props.direction === "left" && "10px"};
right: ${props => props.direction === "right" && "10px"};
margin: auto;
cursor: pointer;
opacity: 0.5;
z-index: 2;
`;
const Wrapper = styled.div`
height: 100%;
display: flex;
transform: translateX({props => props.arrowIndx * -100}vw);
`
const Slide = styled.div`
width: 100vw;
height: 100vw;
display: flex;
align-items: center;
background-color: ${props => props.bg};
`
const ImgContainer = styled.div`
height: 100%;
flex:1;
`
const Image = styled.img`
padding-left: 30px;
align-items: left;
`
const InfoContainer = styled.div`
height: 80%;
flex:1;
padding: 30px;
`
const Title = styled.h1`
font-size: 50px
`
const Desc = styled.p`
margin: 50px 0px;
font-size: 20px;
font-weight: 500;
letter-spacing: 3px;
`
const Button = styled.button`
padding: 10px;
font-size: 20px;
background-color: transparent;
cursor: pointer;
`
const Slider = () => {
const [slideIndx, setSlideIndx] = useState([]);
const [arrowIndx, setArrowIndx] = useState(0);
const handleClick = (direction) => {
if(direction === "left"){
setArrowIndx(arrowIndx > 0 ? arrowIndx - 1 : 2)
} else{
setArrowIndx(arrowIndx < 2 ? arrowIndx + 1 : 0)
}
}
const fetchSliderItems = () => {
fetch('http://localhost:3000/sliderItems')
.then(resp => resp.json())
.then(data => {
console.log(data)
setArrowIndx(data)
setSlideIndx(data)
})
}
useEffect(() => {fetchSliderItems()}, [])
return (
<Container>
<Arrow direction="left" onClick={() => handleClick("left")}>
<ArrowLeftOutlined />
</Arrow>
<Wrapper arrowIndx={arrowIndx}>
{slideIndx.map((item) => (
<Slide bg={item.bg}>
<ImgContainer>
<Image src={item.img}/>
</ImgContainer>
<InfoContainer>
<Title>{item.title}</Title>
<Desc>{item.desc}</Desc>
<Button>SHOP NOW</Button>
</InfoContainer>
</Slide>
))}
</Wrapper>
<Arrow direction="right" onClick={() => handleClick("right")}>
<ArrowRightOutlined />
</Arrow>
</Container>
)
}
export default Slider
{
"sliderItems": [
{
"id": 1,
"img": "../images/model1.png",
"title": "SPRING CLEANING",
"desc": "DONT MISS OUR BEST COLLECTION YET! USE #FLATIRON10 TO RECEIVE 10% OFF YOUR FIRST ORDER",
"bg": "#b3ecff"
},
{
"id": 2,
"img": "../images/model2.png",
"title": "SHOW OFF HOW YOU DRESS",
"desc": "WITH OUR HUGE SELECTION OF CLOTHES WE FIT ALL YOUR STYLING NEEDS",
"bg": "#ccf2ff"
},
{
"id": 3,
"img": "../images/model3.png",
"title": "POPULAR DEALS",
"desc": "RECEIVE FREE SHIPPING ON ALL ORDERS OVER $50!",
"bg": "#fe6f9ff"
}
]
}
if you want to use 2 data at 1 use state you have 2 way to achieve that
store data as cell of array like below.
const [data,setData] = useState([1,2])
console.log(data[1])
set data as Object in useState
const [data,setData] = useState({data1: 1, data2: 2 })
but i suggest you to use second approach because it's easy to use.
one point you must have care about it in this approach is, if you want to update state with object-state you have to update state with deep copy and then react can re-render component
for example if you want to update data2 in object of state you have to dod this
const [data,setData] = useState({data1: 1, data2: 2 })
setData((prevState) => ({
...prevState,
data2: 'value',
}));
white this snippet you will get update data2 and react get re-render
in your case if you want save array and update it and if you want get re-render when pass new array you have to clone new array and pass it into useState and you can archive this with spread operator in JavaScript.
Example:
setData((prevState) => ({
...prevState,
data2: [...newArray],
}));
if you pass newArray instead of [...newArray] you just pass the reference of memory if array into state and if after setState you change newAereay at the rest of code your state will update to and you don't want this.

React - How to pass image url from data map to component?

I'm writing a simple application that displays by mapping matching data from a data.js file.
This is what the data.js file looks like:
export const data = {
destinations: [
{
name: "Moon",
images: {
png: require("../assets/destination/image-moon.png"),
webp: "../assets/destination/image-moon.webp",
},
description:
"See our planet as you’ve never seen it before. A perfect relaxing trip away to help regain perspective and come back refreshed. While you’re there, take in some history by visiting the Luna 2 and Apollo 11 landing sites.",
distance: "384,400 km",
travel: "3 days",
},
{
name: "Mars",
images: {
png: require("../assets/destination/image-mars.png"),
webp: "../assets/destination/image-mars.webp",
},
description:
"Don’t forget to pack your hiking boots. You’ll need them to tackle Olympus Mons, the tallest planetary mountain in our solar system. It’s two and a half times the size of Everest!",
distance: "225 mil. km",
travel: "9 months",
},
{
name: "Europa",
images: {
png: require("../assets/destination/image-europa.png"),
webp: "../assets/destination/image-europa.webp",
},
description:
"The smallest of the four Galilean moons orbiting Jupiter, Europa is a winter lover’s dream. With an icy surface, it’s perfect for a bit of ice skating, curling, hockey, or simple relaxation in your snug wintery cabin.",
distance: "628 mil. km",
travel: "3 years",
},
{
name: "Titan",
images: {
png: require("../assets/destination/image-titan.png"),
webp: "../assets/destination/image-titan.webp",
},
description:
"The only moon known to have a dense atmosphere other than Earth, Titan is a home away from home (just a few hundred degrees colder!). As a bonus, you get striking views of the Rings of Saturn.",
distance: "1.6 bil. km",
travel: "7 years",
},
],
This is what the page code looks like:
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import backgroundImage from "../assets/destination/background-destination-mobile.jpg";
import planet from "../assets/destination/image-moon.png";
// import data from "../data/data.json";
import { data } from "../data/data";
export const Wrapper = styled.div`
height: 100vh;
width: 100vw;
background-image: url(${backgroundImage});
background-repeat: no-repeat;
background-size: cover;
display: flex;
flex-direction: column;
align-items: center;
`;
export const Title = styled.div`
margin-top: 6rem;
color: white;
display: flex;
letter-spacing: 2px;
white-space: nowrap;
`;
export const ImageContainer = styled.div`
width: 80%;
display: flex;
justify-content: center;
align-items: center;
& img {
height: 130px;
width: 130px;
}
`;
export const PlanetChoose = styled.div`
/* background-color: red; */
width: 90%;
display: flex;
justify-content: space-around;
margin-top: 10px;
& p {
color: #d0d6f9;
cursor: pointer;
}
`;
export const ImageTest = styled.img`
width: 150px;
height: 150px;
`;
function Destination() {
const [toggle, setToggle] = useState("");
return (
<Wrapper>
<Title>
<p style={{ marginRight: "10px", color: "grey", fontWeight: "bold" }}>
01
</p>
<p>PICK YOUR DESTINATION</p>
</Title>
<ImageContainer>
//HERE I WANT TO PASS URL FROM MAP
<img src={planet} alt="planet"></img>
</ImageContainer>
<PlanetChoose>
{data.destinations.map(({ name, images }) => {
return (
<>
<p onClick={() => setToggle(name)}>{name}</p>
</>
);
})}
</PlanetChoose>
<h1>{toggle}</h1>
</Wrapper>
);
}
export default Destination;
When I press the 'p' tag the corresponding header and the rest of the data within the mapping is displayed.
The question, however, is how to move the url of an image that is outside the mapping in the ImageContainer?
Set the entire object into your toggle state and either conditionally render the <h1> and <img> or use placeholder values, eg
const [ toggle, setToggle ] = useState({
name: "",
images: {
png: somePlaceholderImage
}
});
return (
<Wrapper>
{/* <Title>...</Title> */}
<ImageContainer>
<img src={toggle.images.png} alt="planet" />
</ImageContainer>
<PlanetChoose>
{data.destinations.map(dest => (
<p
key={dest.name}
onClick={() => setToggle(dest)}
>{dest.name}</p>
))}
</PlanetChoose>
<h1>{toggle.name}</h1>
</Wrapper>
);
You need to do 2 things. First, you need to import the entire image directory into the component file as a single variable. Second, you need to access the correct image by parsing the data file and the value of the "toggle" state.
This first step is important since you cannot access files with just a path string in the JSX. You have to import it so that it is included in the bundle, and then you can import images from that directory later. You can import an entire directory into a variable like this:
import images from '../assets/destination';
Now we can use the moon file, for example, like this:
<img src={images["image-moon.png"]} alt="planet" />
To integrate this into your component, all we have to do is manipulate the toggled planet name so that we can access the right file. We can do that with a simple memo hook that returns the formatted image name (or an empty string, so that the image can be conditionally rendered).
import React, { useState, useEffect, useRef, useMemo } from "react";
import styled from "styled-components";
import backgroundImage from "../assets/destination/background-destination-mobile.jpg";
import { data } from "../data/data";
import images from '../assets/destination';
function Destination() {
const [ toggle, setToggle ] = useState("");
const imageName = useMemo(() =>
toggle.length ? `image-${toggle.toLocaleLowerCase()}.png` : ""
, [toggle]);
return (
<Wrapper>
<Title>
<p style={{ marginRight: "10px", color: "grey", fontWeight: "bold" }}>
01
</p>
<p>PICK YOUR DESTINATION</p>
</Title>
<ImageContainer>
//HERE I WANT TO PASS URL FROM MAP
{imageName.length && <img src={images[imageName]} alt="planet" />}
</ImageContainer>
<PlanetChoose>
{data.destinations.map(({ name, images }) => (
<p onClick={() => setToggle(name)}>{name}</p>
)}
</PlanetChoose>
<h1>{toggle}</h1>
</Wrapper>
);
}

radio group buttons using ant design dont work

I am experiencing some issues with radio group buttons. Can someone help me with this issue. (your help is much appreciated)
Current Issue: Radio Group are not clickable. Im not sure where I missed up!
Technologies Used: React hooks, styled-components , and design
for the radio buttons.
RadioGroup.js
import React from "react";
import { Radio } from "antd";
import styled from "styled-components";
import { theme } from "constants/theme";
const { royalBlue, black } = theme.colors;
const { medium } = theme.typography.size;
const { display } = theme.typography.font.family;
const StyledRadioGroup = styled(Radio.Group)`
width: 100%;
margin-top: 0.5rem;
text-align: left;
.ant-radio-wrapper {
justify-content: space-between;
padding: ${(props) => props.padding};
white-space: break-spaces;
margin-left: -1.5rem;
span.ant-radio + * {
font-family: ${display};
font-size: ${medium};
color: ${black};
letter-spacing: 0;
}
.ant-radio-inner {
border-color: ${royalBlue};
border-width: 0.2rem;
width: 2.5rem;
height: 2.5rem;
&::after {
background-color: ${royalBlue};
top: 0.2rem;
left: 0.2rem;
}
}
}
`;
const RadioGroup = ({
options,
onChange,
value,
defaultValue,
flex,
padding,
}) => {
return (
<StyledRadioGroup
size="large"
flex={flex}
padding={padding}
onChange={onChange}
value={value}
defaultValue={defaultValue}
>
{options.map((option, index) => (
<Radio value={option.stateKey} key={index}>
{option.value}
</Radio>
))}
</StyledRadioGroup>
);
};
export default RadioGroup;
Navigation.js
import React, { useState, useReducer } from "react";
import styled from "styled-components";
import RadioModal from "components/Feedback/RadioModal";
import RadioGroup from "components/Feedback/RadioGroup";
const renderRadioModal = () => {
const inputLabelsText = [
{
stateKey: "age",
label: "What is your age?",
},
];
const radioButtonOptions = [
{
stateKey: "covidImpact",
value: "I go to work/school normally",
},
{
stateKey: "covidImpact",
value: "I am healthy but in a stay-at-home quarantine",
},
{
stateKey: "covidImpact",
value: "I have mild symptoms but haven't been tested",
},
{
stateKey: "covidImpact",
value: "I am diagnosed with Covid-19",
},
];
const RadioGroupWithLabel = withLabel(() => (
<RadioGroup
onChange={true}
options={radioButtonOptions}
value={true}
padding="1rem 1rem"
size="large"
></RadioGroup>
));
return (
<RadioModal
maskClosable={true}
closable={true}
visible={radioModal}
onClose={() => closeRadioModal()}
transparent
>
<h2 className="title">We are almost done!</h2>
{inputLabelsText.map((label, index) => (
<>
<StyledInput
key={index}
label={label.label}
value={label.stateKey}
onChange={dispatchAction}
></StyledInput>
<RadioGroupWithLabel label={"How has COVID-19 impacted you?"} />
</>
))}
<FeedbackSubmitButton
title="Submit Feedback"
onClick={closeRadioModal}
></FeedbackSubmitButton>
</RadioModal>
);
};
You have onChange={true} and value={true}. You need to handle the onChange and value properly. The value prop needs to match the value in your options that you pass into the radio group.
The options you pass in should be in the structure [{ value, label }, { value, label }]
Then in your onChange you need to handle setting that value + have a place to store it

how can i display round dot for active status in react

In older code of react it just display the text active or in active for an user. Now I want to replace it to red or green small dot how can I do it.
CSS
div .colored-circle {
display: inline-block;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -2px;
border-radius: 50%;
border-style: solid;
border-width: 0.5px;
border-color: black;
height: 20px;
width: 20px;
}
Component:
const ColoredCircle = ({ color }) => {
const styles = { backgroundColor: color };
return color ? (
<Fragment>
<span className="colored-circle" style={styles} />
</Fragment>
) : null;
};
export default ColoredCircle;
Use the same logic you used to show 'active' or 'inactive' and instead of text add a div with css or img of the desired color.
If you happen to use material UI, you can do like this:
import React, { Fragment } from "react";
import { makeStyles } from "#material-ui/core";
const RADIUS_DOT = 1.5;
const useStyles = makeStyles((theme) => ({
circle: {
borderRadius: RADIUS_DOT,
height: RADIUS_DOT * 2,
width: RADIUS_DOT * 2,
padding: 0,
},
}));
const ColoredCircle = ({ color }) => {
const styles = { backgroundColor: color };
const classes = useStyles();
return color ? (
<Fragment>
<span className={classes.circle} style={styles} />
</Fragment>
) : null;
};
export default ColoredCircle;
you can use this package, can be helpful
npm i react-color-circle
import Circle from '#uiw/react-color-circle';
return (
<Circle
colors={[ '#F44E3B' ]}
/>);

How to change size of Toggle Switch in Material UI

This is my first time using Material UI (I'm also a noob with react in general) and I cant seem to change the size of the toggle switch I'm using.
This is what I have so far -minus all the non related stuff:
import React, { Component } from "react";
import Switch from "#material-ui/core/Switch";
const styles = {
root: {
height: "500",
},
};
class ToggleActive extends Component {
state = {
checked: true,
};
handleChange = name => event => {
this.setState({ [name]: event.target.checked });
};
render() {
return (
<label htmlFor="normal-switch">
<Switch
classes={styles.root}
checked={this.state.checked}
onChange={this.handleChange("checked")}
/>
</label>
);
}
}
export default ToggleActive;
I just want to make it a bit larger, and change the color. Any help would be appreciated!
The change in the Switch component requires a little bit of detailed styling. I added some comments in parts that are not very obvious:
import {createStyles, makeStyles, Switch, Theme} from '#material-ui/core';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
width: 54,
height: 40,
padding: 0,
margin: theme.spacing(1),
},
switchBase: {
padding: 1,
'&$checked': {
// This is the part that animates the thumb when the switch is toggled (to the right)
transform: 'translateX(16px)',
// This is the thumb color
color: theme.palette.common.white,
'& + $track': {
// This is the track's background color (in this example, the iOS green)
backgroundColor: '#52d869',
opacity: 1,
border: 'none',
},
},
},
thumb: {
width: 36,
height: 36,
},
track: {
borderRadius: 19,
border: `1px solid ${theme.palette.grey[300]}`,
// This is the background color when the switch is off
backgroundColor: theme.palette.grey[200],
height: 30,
opacity: 1,
marginTop: 4,
transition: theme.transitions.create(['background-color', 'border']),
},
checked: {},
focusVisible: {},
})
);
You can implement this as a functional component:
import React, { useState } from 'react';
// import {createStyles, makeStyles, ...
// const useStyles = makeStyles((theme: Theme) => ...
export const ToggleItem: React.FC = () => {
const styles = useStyles();
const [toggle, setToggle] = useState<boolean>(false);
return (
<Switch
classes={{
root: styles.root,
switchBase: styles.switchBase,
thumb: styles.thumb,
track: styles.track,
checked: styles.checked,
}}
checked={toggle}
onChange={() => setToggle(!toggle)}
name={title}
inputProps={{'aria-label': 'my toggle'}}
/>
);
};
This is now even easier to accomplish because MUI has an official example in the documentation:
https://mui.com/material-ui/react-switch/#customization
Using that as an example, the minimum number of changes to accomplish making the switch bigger is actually just this:
export const MuiSwitchLarge = styled(Switch)(({ theme }) => ({
width: 68,
height: 34,
padding: 7,
"& .MuiSwitch-switchBase": {
margin: 1,
padding: 0,
transform: "translateX(6px)",
"&.Mui-checked": {
transform: "translateX(30px)",
},
},
"& .MuiSwitch-thumb": {
width: 32,
height: 32,
},
"& .MuiSwitch-track": {
borderRadius: 20 / 2,
},
}));
Here is the link to a forked sandbox with just a bigger switch:
https://codesandbox.io/s/customizedswitches-material-demo-forked-4m2t71
Consider this: I am not a front-end developer and did not develop in
Material-UI framework for years now. so just look for a different answer or send
me an edit version which works.
For changing the size of the switch component you should use size props that can be in two size 'small' || 'medium'.For example:
<Switch
size="small"
checked={this.state.checked}
onChange={this.handleChange("checked")}
color='primary'
/>
If it doesn't work for you then You need to change CSS style at root class:
const styles = {
root: {
height: 500,
width: 200},
};
Due to material-UI component API for changing the color of a switch you need to add a color props into you Switch JSX tag and choose from these enum:
enum: 'primary' |'secondary' | 'default'
your Switch should be like this:
<Switch
classes={styles.root}
checked={this.state.checked}
onChange={this.handleChange("checked")}
color='primary'
/>
Material-UI for switch size prop

Categories