I'm still a beginner in JavaScript and ReactJS. I'm doing a project to improve my knowledge.
I'm rendering a list where the user can filter results by star, as shown in the image below:
The way I created this list is not at all smart:
import React from "react";
import "./styles.css";
import Checkbox from "#material-ui/core/Checkbox";
import StarBorderIcon from "#material-ui/icons/StarBorder";
import { useStyles } from "./styles";
export default function App() {
const classes = useStyles();
return (
<div className="App">
<h1>Start</h1>
<div className={classes.root}>
<Checkbox />
<StarBorderIcon />
</div>
<div className={classes.root}>
<Checkbox />
<StarBorderIcon />
<StarBorderIcon />
</div>
<div className={classes.root}>
<Checkbox />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
</div>
<div className={classes.root}>
<Checkbox />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
</div>
<div className={classes.root}>
<Checkbox />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
<StarBorderIcon />
</div>
</div>
);
}
Can you tell me how to render this list, up to a total of 5 stars (as shown in the image), always adding one star to my list?
I put my code into codesandbox
Thank you very much in advance.
You can create and map over an array of specified length in order to create the individual sections and stars.
I'm using new Array(number).fill(null) since I want to create an array of a certain length and map over it. The .fill(null) is to get rid of the special empty values in an array constructed like this so that they are mapable.
You could have the logic all in one place, or you could convert pieces of the logic to separate components to simplify your main component.
Essentially in this we have 2 nested loops to render the checkboxes and the appropriate stars. The same is true whether you move the sub loop into it's own component (the Stars component in this example).
import React from "react";
import "./styles.css";
import Checkbox from "#material-ui/core/Checkbox";
import StarBorderIcon from "#material-ui/icons/StarBorder";
import { useStyles } from "./styles";
const array = new Array(5).fill(null);
export default function App() {
const classes = useStyles();
return (
<div className="App">
<h1>Start</h1>
{array.map((_val, idx) => (
<div key={idx} className={classes.root}>
<Checkbox />
{new Array(idx + 1).fill(null).map((_val, idx2) => (
<StarBorderIcon key={idx2} />
))}
</div>
))}
{/* Move some logic to a separate component */}
{array.map((_val, idx) => (
<div key={idx} className={classes.root}>
<Checkbox />
<Stars number={idx + 1} />
</div>
))}
</div>
);
}
function Stars({ number }) {
return new Array(number)
.fill(null)
.map((_val, idx) => <StarBorderIcon key={idx} />);
}
https://codesandbox.io/s/render-stars-icon-forked-wxtx4?file=/src/App.js
Related
I am using the react-bootstrap carousel component here: https://react-bootstrap.github.io/components/carousel/) and I am trying to set the 'defaultActiveIndex' prop (not mentioned in docs but it allows the carousel to keep autoplaying instead of using 'activeIndex' prop which prevents autoplay).
By setting this property through a button click, I want to set 'defaultActiveIndex', which should change the Carousel current position and then continue autoplaying afterwards.
I have this code in the component that holds the carousel state:
const [carouselIndex, setCarouselIndex] = useState(0);
function handleClick(e, param){
setCarouselIndex(param);
};
and the same component returns this:
<button onClick={(e) => handleClick(e, 3)}>Filter</button>
And the Carousel within the same component has the following props:
<Carousel
className='carousel'
variant='dark'
fade={true}
controls={true}
slide={true}
indicators={false}
interval={1300}
defaultActiveIndex={carouselIndex}
Currently I can see the handleClick function tracking the '3' coming from the button as param, but the 'setCarouselIndex' setter is not working and does not set 'carouselIndex' in the 'defaultActiveIndex' Carousel prop.
Full component code:
import React, { useEffect, useState } from 'react';
import Carousel from 'react-bootstrap/Carousel';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import './../App.css';
function Product(props) {
const [carouselIndex, setCarouselIndex] = useState(0);
function handleClick(e, param){
setCarouselIndex(param);
};
return (
<div>
<Row>
<Col>
</Col>
<Col>2</Col>
<Col>3</Col>
</Row>
<Row>
<Col>
</Col>
<Col>
<Carousel
className='carousel'
variant='dark'
fade={true}
controls={true}
slide={true}
indicators={false}
interval={1300}
defaultActiveIndex={carouselIndex}
>
{props.products.map(product =>
<Carousel.Item
key={product.product_id}
className="carousel-item"
>
<div>
<img
className="d-block w-100"
src={product.image_url}
alt=""
style={{
borderRadius:"5px",
}}
/>
<div className="product-card-info"
style={{
borderRadius:"5px",
}}
>
<p>Name: {product.product_name}</p>
<p>Description: {product.description}</p>
<p>Sizes(s): {product.size}</p>
<p>{product.currency} {product.price}</p>
<p>Delivery cost: {product.delivery_cost}</p>
<p>{product.in_stock}</p>
<p><a href={product.deeplink}>
<span><i></i> Visit Product </span>
</a>
</p>
<p><button onClick={(e) => handleClick(e, 3)}>Filter</button></p>
</div>
</div>
</Carousel.Item>
)}
</Carousel>
</Col>
<Col>
</Col>
</Row>
<Row>
<Col>1</Col>
<Col></Col>
</Row>
</div>
)
}
export default Product;
Any ideas or tips for how I could get this to work would be very much appreciated.
Thanks for your time all.
function App() {
const [people, setPeople] = useState([
{
name: "Model Baby",
url:"https://www.themodelskit.co.uk/wp-
content/uploads/2021/10/shutterstock_1431963185.jpg"
},
{
name: "Seema Jaswal",
url:"https://static.standard.co.uk/2021/06/14/16/euro_2020_live_seema_jaswal_01-1.jpg?
width=968&auto=webp&quality=50&crop=968%3A645%2Csmart"
},
{
name: 'Plaboi Baby',
url: '../assets/IMG_20210811_105110_849.webp'
}
]);
const [per, setPer] = useState(people.name);
return (
<div className="app">
I am try to update my sidebar from the data above, i am trying to track changes in my sidebar from the main app, how do i effectively deploy useState or context API for this purpose
<Routes>
<Route path='/explore' element={<>
<div className='app__tinder'>
<TinderCards people={people} setPer={setPer} />
<SwipeButtons />
</div>
<aside className='app__sidebar right'>
<RightSidebar per={per} />
</aside>
</div>
</div>
</>} />
</div>
);
}
export default App;
TinderCard.js i need the name and age here to update on the sidebar when it changes
function TinderCards({people, setPer}) {
return (
<div>
<div className='tinderCards__cardContainer'>
{people.map((person) => (
<TinderCard className="swipe" key={person.name} preventSwipe={["up, down"]} onClick=
{() => {setPer(person.name)}} >
<div className='card' style={{ backgroundImage: `url(${person.url})`}}>
<h3>{person.name}</h3>
</div>
</TinderCard>
))}
</div>
</div>
)
}
export default TinderCards
RightSidebar, i tried applying useState but i am not sure that i am using it properly, pls help
function RightSidebar({per}) {
console.log("move", per)
return (
<div className='rightSidebar'>
{/* {people.map((person) => ( */}
<div className='rightSidebar__contents'>
<h1>About</h1>
<Card className='rightSidebar__card'>
<div className='card__nameContents'>
<CardHeader className='card__nameAge' title = {per.name} subheader =
{per.age} avatar =
{<VerifiedIcon className='activeIcon verified' />} />
<CardHeader className='card__active' title = "active" avatar=
{<FiberManualRecordIcon className='activeIcon' />} />
</div>
i am trying to put conditions on the Button, in my component. I have a Boolean condition from my Firebase collection for lastRunStatus {cloundFunctions.lastRunStatus} and if it's true i was it to stay green and say 'Cloud Function' and if its false i want it to turn red and say 'somethings wrong.
Any tips, pointers, or code would be highly appreciated :)
import "../../App";
import "semantic-ui-css/semantic.min.css";
import { Icon, Card, Button } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import React from "react";
import "semantic-ui-css/semantic.min.css";
import moment from "moment";
const Cards = ({ cloudFunction }) => {
return (
<Card color="green">
<Card.Content>
<Card.Header>{cloudFunction.id}</Card.Header>
</Card.Content>
<Card.Content extra>
<Icon name="cog" /> Records: {cloudFunction.lastRunLoad}
<br />
<Icon name="cog" />
{cloudFunction.lastRunMessage}
<br />
<Icon name="clock" /> Last Run:{" "}
{moment(cloudFunction.lastRunTime.toDate().toString()).format(
"DD/MM/YYYY HH:mm",
true
)}
<br />
<Icon name="angle double down" />
Schedule: {cloudFunction.schedule}
</Card.Content>
<Card.Content extra>
<div className="ui two buttons">
<Button
basic
type="button"
color="green"
onClick={(e) => {
e.preventDefault();
window.open(cloudFunction.url.toString(), "_blank");
}}
>
Cloud Function
</Button>
</div>
</Card.Content>
</Card>
);
};
export default Cards;
Look at conditions in React. If I understand your correctly, you can do something like:
{cloundFunctions.lastRunStatus ? (
<Button
basic
type="button"
color="green"
onClick={(e) => {
e.preventDefault();
window.open(cloudFunction.url.toString(), "_blank");
}}
>
Cloud Function
</Button>
) : (
<div>Something's wrong</div>
)
I'm fairly new to React and what to understand how I can (if it's possible) change prop values for nested components at page level.
Here's an example of what I mean:
I have a component called Text
I have a component called Image
I have a component called TextImage
In TextImage, I am using both Text and Image components. Both of these nested components have their own props.
Now, I cannot define these prop values in the TextImage component itself, because I may need to use the TextImage component multiple times on my page.
Here is Text.js:
import React from 'react';
class Text extends React.Component{
render() {
const header = this.props.header;
const copy = this.props.copy;
return(
<section className="text">
<h2 className="text__header">{ header }</h2>
<div className="text__copy">{ copy }</div>
</section>
)
}
}
export default Text;
Here is Image.js:
import React from 'react';
class Image extends React.Component{
render() {
const image_src = this.props.image_src;
const image_alt = this.props.image_alt;
return(
<section className="image">
<img loading="lazy" src={ image_src } alt={ image_alt } />
</section>
)
}
}
export default Image;
And here is TextImage.js (in its current form):
import React from 'react';
import { Container, Row, Col } from 'react-bootstrap';
import Text from '../Text/Text';
import Image from '../Image/Image';
import "./TextImage.scss";
class TextImage extends React.Component{
render(){
return(
<section className="textImage">
<Container>
<Row>
<Col md={6}>
<Text />
</Col>
<Col md={6}>
<Image/>
</Col>
</Row>
</Container>
</section>
)
}
}
export default TextImage;
I cannot do something like the below, because then those props will be consistent for whenever I use the TextImage component.
<section className="textImage">
<Container>
<Row>
<Col md={6}>
<Text header="This is header" copy="this is copy" />
</Col>
<Col md={6}>
<Image image_src="" image_alt="image" />
</Col>
</Row>
</Container>
</section>
In my Homepage.js file, I have tried to do something like this:
<TextImage header="test" /> which I kind of knew beforehand wouldn't work as the props are assigned to the Text and Image components within TextImage.
I can easily output my TextImage markup in Homepage.js (like below), but I'm looking for a cleaner approach.
import React from "react";
import Text from "../components/Text/Text";
import Image from "../components/Image/Image";
function Homepage() {
return (
<>
<section className="textImage">
<Container>
<Row>
<Col md={6}>
<Text header="This is header" copy="this is copy" />
</Col>
<Col md={6}>
<Image image_src="" image_alt="image" />
</Col>
</Row>
</Container>
</section>
</>
);
}
export default Homepage;
You just need to pass the props which are used in Text and Image to TextImage component as below.
Demo at : https://codesandbox.io/s/gallant-golick-zkmdi?file=/src/App.js
import "./styles.css";
import React from "react";
class Text extends React.Component {
render() {
const header = this.props.header;
const copy = this.props.copy;
return (
<section className="text">
<h2 className="text__header">{header}</h2>
<div className="text__copy">{copy}</div>
</section>
);
}
}
class Image extends React.Component {
render() {
const image_src = this.props.image_src;
const image_alt = this.props.image_alt;
return (
<section className="image">
<img loading="lazy" src={image_src} alt={image_alt} />
</section>
);
}
}
class TextImage extends React.Component {
render() {
const image_src = this.props.image_src;
const image_alt = this.props.image_alt;
const header = this.props.header;
const copy = this.props.copy;
return (
<section className="textImage">
<div>
<div>
<div md={6}>
<Text header={header} copy={copy} />
</div>
<div md={6}>
<Image image_alt={image_alt} image_src={image_src} />
</div>
</div>
</div>
</section>
);
}
}
export default function App() {
return (
<div className="App">
<TextImage header='Random Header' copy='RandomCopy' image_src='https://picsum.photos/200/300' image_alt='randomImage' />
<TextImage header='Random Header2' copy='RandomCopy2' image_src='https://picsum.photos/300/300' image_alt='randomImage2' />
</div>
);
}
I have to use multiple dropdowns from semantic-ui-react in my project. They need to have different props. It looks like this
<div className="wrapper">
<img className="icon" src={iconA} alt="iconA"></img>
<h1>A</h1>
<Dropdown
className="dropdown"
search
selection
options={optionsA}
placeholder="A"
defaultValue="A"
onChange={handleAChange}
/>
</div>
<div className="wrapper">
<img className="icon" src={iconB} alt="iconB"></img>
<h1>B</h1>
<Dropdown
className="dropdown"
search
selection
options={optionsB}
placeholder="B"
defaultValue="B"
onChange={handleBChange}
/>
</div>
I want to refactor this and create a single component for this by pasing different props. Please guide me on how this can be refactored in the best way possible.
First, create your custom dropDown component and extract props using object destructuring, you can give deafult values to props there itself, but better use PropTypes for that.
const CustomDropDown = (props) => {
const {
className,
search,
selection,
options,
placeholder,
defaultValue,
onChange
} = props;
return (
<div className="wrapper">
<img className="icon" src={iconA} alt="iconA"></img>
<h1>A</h1>
<Dropdown
className={classname}
search={search}
selection={selection}
options={optionsA}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={onChange}
/>
</div>
)
}
Now, call the component like this,
<CustomDropDown
className="dropdown"
search
selection
options={optionsA}
placeholder="A"
defaultValue="A"
onChange={handleAChange}
/>
You can do it as follows:
const DropDownWraper = ({
header,
options,
onChange,
iconProps,
placeholde,
defaultValue
}) =>
<div className="wrapper">
<img
className="icon"
src={ iconProps.src }
alt={ iconProps.alt } />
<h1>{ header }</h1>
<Dropdown
search
selection
options={ options }
className="dropdown"
onChange={ onChange }
placeholder={ placeholde }
defaultValue={ defaultValue } />
</div>