React Display component after click on card - javascript

I creating simple app. It must be app with information about pokemons. So I need to create, when user click on pokeCard, Sidebar info.
How it look now:
So, Sidebar is must to be, it can be, for example, only white background.
I think about styled-components, but I not sure, that this would be the right decision
How to do it with functional Component?
Wrapper
const [SelectedPokemonIndex, setSelectedPokemonIndex] = useState();
return (
<Row>
<Col xs={24} sm={14} lg={16}>
<Pokemons
PokemonsList={PokemonsList}
loadMoreItems={loadMoreItems}
Loading={Loading}
onClickPoke={(pokemonId) => {
fetchPokemonDetails(pokemonId);
fetchPokemon(pokemonId);
fetchPokemonStats(pokemonId);
setSelectedPokemonIndex(pokemonId);
}}
/>
</Col>
<Col xs={24} sm={10} lg={8}>
<About
pokemon={SelectedPokemon}
PokemonTypes={PokemonTypes}
PokemonStats={PokemonStats}
index={SelectedPokemonIndex}
LoadingForSelectedPokemon={LoadingForSelectedPokemon}
/>
</Col>
</Row>
);
}
export default Wrapper;
Child component of wrapper
function Pokemons(props) {
let { PokemonsList, loadMoreItems, Loading, onClickPoke } = props;
return (
<GridCard
image={`${IMAGE_BASE_URL}${++index}.png`}
pokemonId={index}
pokemonName={pokemon.name}
pokemonUrl={pokemon.url}
onClickPoke={onClickPoke}
/>
PokeCard
import React, { useEffect, useState } from "react";
import { Col, Typography } from "antd";
import "./GridCards.css";
const { Title } = Typography;
function GridCards(props) {
let { key, image, pokemonName, pokemonUrl, pokemonId } = props;
return (
<Col
key={key}
lg={8}
md={12}
xs={24}
onClick={() => {
props.onClickPoke(pokemonId);
}}
>
<div
className="poke-card"
}}
>
<img alt={pokemonName} src={image} />
{LoadingForPokemon && <div>Loading...</div>}
</div>
</Col>
);
}
export default GridCards;
This is Sidebar, what must to be change:
function About(props) {
let {
pokemon,
LoadingForSelectedPokemon,
index,
PokemonTypes,
PokemonStats,
} = props;
return (
<div
style={{
position: "sticky",
top: 0,
display: "flex",
justifyContent: "center",
}}
>
<PokemonDetails
pokemonName={pokemon.name}
pokemonId={pokemon.id}
pokemon={pokemon}
LoadingForSelectedPokemon={LoadingForSelectedPokemon}
image={`${IMAGE_BASE_URL}${index}.png`}
PokemonTypes={PokemonTypes}
PokemonStats={PokemonStats}
/>
</div>
);
}

This is a pretty broad question and there's a lot going on in your code, but I think you need to move some state management around.
In your GridCards component, give it a prop called onCardClick and call that function in the onClick of the <Col> component you're using. It'll look something like this:
function GridCard(props) {
const { key, image, pokemonName, pokemonUrl, pokemonId, onCardClick } = props;
return (
<Col
key={key}
lg={8}
md={12}
xs={24}
onClick={() => onCardClick()}
>
<div
className="poke-card"
>
<img alt={pokemonName} src={image} />
{LoadingForPokemon && <div>Loading...</div>}
</div>
</Col>
);
}
export default GridCard;
Then in your wrapper components, instead of using the Pokemons component, I think you can just use your GridCard component and map on whatever data you're using to render out the cards currently.
So something like this:
export default function Wrapper() {
const [selectedPokemon, setSelectedPokemon] = useState(null);
// data is whatever you have to iterate over to put data into your cards
const pokemonCards = data.map((p, idx) => {
return (
<GridCard
key={idx}
image={p.image}
pokemonName={p.pokemonName}
onCardClick={() => setSelectedPokemon(p)}
></GridCard>
);
});
return (
<Row>
<Col xs={24} sm={14} lg={16}>
{pokemonCards}
</Col>
<Col xs={24} sm={10} lg={8}>
<About pokemon={selectedPokemon} />
</Col>
</Row>
);
}
Basically, what you should try and accomplish is letting each GridCard component contain all the necessary information for your About component, so that when you click on a GridCard your Wrapper's state can update with a selectedPokemon and then pass that back down into your About component.

I found solution for my question.
Its only need to set isAboutShown
const [isAboutShown, setAboutShow] = useState(false);
And onClick I coding setAboutShow(true)
How to display component?
{isAboutShown && (
<About/>)

Related

how i get querySelectorAll html elements in react?

I am using react with functional component. I also use react-bootstrap , I attached the react-bootstrap carousel , everything is fine with react-bootstrap, for some functionality, I want to get three divs in react , divs has same classes. I know if I use simple html css js then I easily do that,
querySelectorAll(".indicator-btn")
but i want this on react. How can I do that? please suggest me a best practices for that.
This is a my component , in the last i have three divs which i want for Dom.
import React, { useState } from "react";
import Cardcarousel from "./Cardcarousel";
import { Carousel } from "react-bootstrap";
import Brand1img from "../images/brand1.png";
import Airbnbimg from "../images/Airbnb.png";
import Microsoft from "../images/microsoft.png";
import { Row, Col } from "react-bootstrap";
function Carouselx() {
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
console.log(selectedIndex, "e=>", e);
setIndex(selectedIndex);
};
const isSlide = (slide) => {
console.log("slide no => " + slide);
console.log(this);
};
return (
<>
<div className="px-5 py-3">
<Carousel activeIndex={index} onSelect={handleSelect} onSlide={isSlide}>
<Carousel.Item>
<Row>
<Col>
<Cardcarousel
name="Technology UI/UX"
companylogo={Brand1img}
type="Full time job"
/>
</Col>
<Col>
<Cardcarousel
name="Technology Backend developer"
companylogo={Airbnbimg}
type="Part time job"
/>
</Col>
<Col>
<Cardcarousel
name="Technology Backend developer"
companylogo={Microsoft}
type="Internee"
/>
</Col>
</Row>
</Carousel.Item>
<Carousel.Item>
<Row>
<Col>
<Cardcarousel
name="Technology UI/UX"
companylogo={Brand1img}
type="Full time job"
/>
</Col>
<Col>
<Cardcarousel
name="Technology Backend developer"
companylogo={Airbnbimg}
type="Part time job"
/>
</Col>
<Col>
<Cardcarousel
name="Technology front end developer"
companylogo={Microsoft}
type="Internee"
/>
</Col>
</Row>
</Carousel.Item>
</Carousel>
<div className="carusel-indecator-container">
<div className="indicator-btn indicator-btn1"></div>
<div className="indicator-btn indicator-btn2"></div>
<div className="indicator-btn indicator-btn3"></div>
</div>
</div>
</>
);
}
export default Carouselx;
You could use useState to get its refs (also useRef but there'll be a lot more inconveniences potentially).
const [btn1, setBtn1] = useState();
const [btn2, setBtn2] = useState();
const [btn3, setBtn3] = useState();
...
<div ref={setBtn1} className="indicator-btn indicator-btn1"></div>
<div ref={setBtn2} className="indicator-btn indicator-btn2"></div>
<div ref={setBtn3} className="indicator-btn indicator-btn3"></div>
At some point (after 1st rendering) you'll have btn1, btn2, btn3 as button elements. If you want to use it, assumingly imperatively, you could useEffect
useEffect(() => {
if (!btn1 || !btn2 || !btn3) return;
// do something with these refs i.e. make them jquery! $(btn1)
}, [btn1, btn2, btn3]);

React-Bootstrap - How to create rows of 4 cards each?

how do I set the number of cards per row? I need 4 cards to be in one row of mine.
I have been trying for hours.. can't figure out what i do wrong..
I was getting all sorts of errors when i played around with this.
like this one :
here
my package.json file:
thanks!
:)
import { React } from 'react';
import { Card, Button, CardGroup } from 'react-bootstrap';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
const MyDishes = props => {
const { dishes } = props;
return (
<CardGroup style={{display: 'flex', flexDirection: 'row'}}>
{dishes.length > 0 &&
dishes.map(d => (
<Row xs={1} md={2} className="g-4">
{Array.from({ length: 4 }).map((_, idx) => (
<Col>
<Card key={d.id} style={{ width: '100em' }} style={{flex: 1}}>
<Card.Img variant="top" src={d.attributes.picture} />
<Card.Body>
<Card.Title>{d.attributes.name}</Card.Title>
<Card.Text>Possibly some text here</Card.Text>
<Link to={`/dishes/${d.id}`}>
<Button variant="primary">Full Recipe</Button>
</Link>
</Card.Body>
</Card>
</Col>
))}
</Row>
</CardGroup>
);
};
const mapStateToProps = state => {
return {
dishes: state.myDishes
};
};
export default connect(mapStateToProps)(MyDishes);
i get this error now :
To use bootstrap layout system, must use <Container> to wrap <Row> and <Col>
You don't need custom styles to achieve that you want.
import { React } from 'react';
import { Container, Card, Button, CardGroup } from 'react-bootstrap';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
const MyDishes = props => {
const { dishes } = props;
return (
<Container>
{dishes.length > 0 &&
dishes.map(d => (
<Row xs={1} md={2} className="g-4">
{Array.from({ length: 4 }).map((_, idx) => (
<Col>
<Card key={d.id}>
<Card.Img variant="top" src={d.attributes.picture} />
<Card.Body>
<Card.Title>{d.attributes.name}</Card.Title>
<Card.Text>Possibly some text here</Card.Text>
<Link to={`/dishes/${d.id}`}>
<Button variant="primary">Full Recipe</Button>
</Link>
</Card.Body>
</Card>
</Col>
))}
</Row>
))}
</Container>
);
};
const mapStateToProps = state => {
return {
dishes: state.myDishes
};
};
export default connect(mapStateToProps)(MyDishes);

change Component name with map function

I am trying to change component name.
It is normally like <Dashboard/> and <Table/>. But I want to make like
const names = [ {"name":Dashboard},{"name":Table}]
names.map(c => { <c.name />}
render(){
return(
{names.map(c => {
<Panel>
<Panel.Body>
<Row>
<Col md={4}>
<FormControl
/>
</Col>
</Row>
<hr />
<c.name bla={bla} />
<hr />
</Panel.Body>
</Panel>
)}
According to the doc, you need to declare a capitalized variable first:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
and then you can call your component name by using your variable.
And in your case, it would be :
{names.map((c) => {
const CapitalizedComponent = c.name;
return <CapitalizedComponent />;
})}
Please also notice that the map function in your code didn't return anything.
working example in sandbox

How to render React component with passed in props on click

I am making a Menu using React and Redux but am currently having an issue rendering the items when the user selects a category.
My goal is to render a list of items nested in the redux state of a particular category when it is clicked.
In Categories.js, it loads the categories from the redux store and displays them.
import React, { Component } from "react";
import { connect } from "react-redux";
import CategoryItems from "./CategoryItems"
import {
Card,
CardTitle,
CardImg,
Container,
Row,
Col,
CardBody,
Button
} from "shards-react";
class Categories extends Component {
handleClick = category => {
alert(category.title);
return (
<CategoryItems
category={category}
/>
);
};
render() {
let categoryList = this.props.categories.map(category => {
return (
<div key={category.id}>
<Col>
<Card
key={category.id}
onClick={() => {
this.handleClick(category);
}}
>
<CardBody>
<CardTitle>{category.title}</CardTitle>
</CardBody>
</Card>
</Col>
</div>
);
});
return (
<Container>
<Row>{categoryList}</Row>
</Container>
);
}
}
const mapStateToProps = state => {
return {
categories: state.categories,
};
};
export default connect(mapStateToProps)(Categories);
When a category is clicked, (the alert was just so I could make sure data made it) I have it set to render the items Array nested within the selected category.
import React, { Component } from 'react'
import {
Card,
CardTitle,
CardImg,
Container,
Row,
Col,
CardBody,
Button
} from "shards-react";
export class CategoryItems extends Component {
render() {
let items = this.props.category.items;
let categoryItems = items.map(item => {
return (
<Col className="">
<Card
className="mt-2 mb-2 item-col"
style={{ maxWidth: "500px" }}
key={item.id}
>
<CardBody>
<CardTitle style={{ position: "absolute", top: 20, right: 20 }}>
{item.title}
</CardTitle>
<CardImg
style={{ maxWidth: "200px" }}
src={item.img}
alt={item.title}
/>
<span
style={{ position: "absolute", bottom: 40, right: 100 }}
to="/"
// onClick={() => {
// this.handleClick(item.id);
// }}
>
<Button pill theme="info">
+
</Button>
</span>
<div style={{ position: "absolute", bottom: 40, right: 20 }}>
${item.price}
</div>
</CardBody>
</Card>
</Col>
);
});
return (
<Container className="menu-item-cont">
<Row>{categoryItems}</Row>
</Container>
);
}
}
export default CategoryItems
This part does not render the items and I don't get an error message.
I have also tried placing the items I would like rendered directly into the state just to see if I could get them to render on click similar to how the Categories.js is with no luck.
I am somewhat new to react so please forgive me if this is a beginner question.
Any help is appreciated as I have spent hours trying to figure this out.
The problem is that you're not rendering what gets returned from handleClick. What you need is a conditional render in the JSX, then determine whether or not to render the elements depending on a controlled flag variable in the state.
class Categories extends Component {
constructor() {
this.state = {
show: false,
category: undefined
}
this.toggle = (category) => {
this.setState({ show: !this.state.show, category })
}
}
render() {
let categoryList = this.props.categories.map(category => {
return (
<div key={category.id}>
<Col>
<Card
key={category.id}
onClick={e => this.toggle(category)}
>
<CardBody>
<CardTitle>{category.title}</CardTitle>
</CardBody>
</Card>
</Col>
</div>
);
});
return ([
<Container>
<Row>{categoryList}</Row>
</Container>,
(
this.state.show
? <CategoryItems category={this.state.category}/>
: null
)
]);
}
}

pass multiple refs to child components

Before diving to the main problem, my use case is I am trying to handle the scroll to a desired section. I will have navigations on the left and list of form sections relative to those navigation on the right. The Navigation and Form Section are the child component. Here is how I have structured my code
Parent.js
const scrollToRef = ref => window.scrollTo(0, ref.current.offsetTop);
const Profile = () => {
const socialRef = React.useRef(null);
const smsRef = React.useRef(null);
const handleScroll = ref => {
console.log("scrollRef", ref);
scrollToRef(ref);
};
return (
<>
<Wrapper>
<Grid>
<Row>
<Col xs={12} md={3} sm={12}>
<Navigation
socialRef={socialRef}
smsRef={smsRef}
handleScroll={handleScroll}
/>
</Col>
<Col xs={12} md={9} sm={12}>
<Form
socialRef={socialRef}
smsRef={smsRef}
/>
</Col>
</Row>
</Grid>
</Wrapper>
</>
);
};
Navigation.js(child component)
I tried using forwardRef but seems like it only accepts one argument as ref though I have multiple refs.
const Navigation = React.forwardRef(({ handleScroll }, ref) => {
// it only accepts on ref argument
const items = [
{ id: 1, name: "Social connections", pointer: "social-connections", to: ref }, // socialRef
{ id: 2, name: "SMS preference", pointer: "sms", to: ref }, // smsRef
];
return (
<>
<Box>
<UL>
{items.map(item => {
return (
<LI
key={item.id}
active={item.active}
onClick={() => handleScroll(item.to)}
>
{item.name}
</LI>
);
})}
</UL>
</Box>
</>
);
});
export default Navigation;
Form.js
I do not have idea on passing multiple refs when using forwardRef so for form section I have passed the refs as simple props passing.
const Form = ({ socialRef, smsRef }) => {
return (
<>
<Formik initialValues={initialValues()}>
{({ handleSubmit }) => {
return (
<form onSubmit={handleSubmit}>
<Social socialRef={socialRef} />
<SMS smsRef={smsRef} />
</form>
);
}}
</Formik>
</>
);
};
Social.js
const Social = ({ socialRef }) => {
return (
<>
<Row ref={socialRef}>
<Col xs={12} md={3}>
<Label>Social connections</Label>
</Col>
<Col xs={12} md={6}></Col>
</Row>
</>
);
};
Can anyone help me at passing multiple refs so when clicked on the particular navigation item, it should scroll me to its respective component(section).
I have added an example below. I have not tested this. This is just the idea.
import React, { createContext, useState, useContext, useRef, useEffect } from 'react'
export const RefContext = createContext({});
export const RefContextProvider = ({ children }) => {
const [refs, setRefs] = useState({});
return <RefContext.Provider value={{ refs, setRefs }}>
{children}
</RefContext.Provider>;
};
const Profile = ({ children }) => {
// ---------------- Here you can access refs set in the Navigation
const { refs } = useContext(RefContext);
console.log(refs.socialRef, refs.smsRef);
return <>
{children}
</>;
};
const Navigation = () => {
const socialRef = useRef(null);
const smsRef = useRef(null);
const { setRefs } = useContext(RefContext);
// --------------- Here you add the refs to context
useEffect(() => {
if (socialRef && smsRef) {
setRefs({ socialRef, smsRef });
}
}, [socialRef, smsRef, setRefs]);
return <>
<div ref={socialRef}></div>
<div ref={smsRef}></div>
</>
};
export const Example = () => {
return (
<RefContextProvider>
<Profile>
<Navigation />
</Profile>
</RefContextProvider>
);
};

Categories

Resources