How to render React component with passed in props on click - javascript

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
)
]);
}
}

Related

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);

React Display component after click on card

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/>)

How to share state between React function and re-render on changes

I have a react component that renders a forms with checkboxes and a chart (Victory). I want the component to show the active checkboxes in the graph (each checkboxes has its api url, for simplicity, the code below shows useless data and no fetching). There are multiple problems in this code:
1) The activestock state always seem to be one step behind in the point of view of the console.log, in the console it show the previous state instead of the actual content of the array. But in the React Dev Tools it shows the activestock correctly.
2) The VictoryChart doesnt get re-rendered even though its props (which is the activestock) changes, even though I can see in the React Dev Tools that multiple VictoryLines components exist. It's like the parents doesn't rerender on state changes, but I thought that by passing a state in props, you shared state between components?
3) Because the hooks rerenders the components, the checkboxes doesn't show a check when clicked.
Here is a sandbox link: https://codesandbox.io/s/crazy-murdock-3re1x?fontsize=14&hidenavigation=1&theme=dark
import React, {useState, useEffect}from 'react'
import Card from 'react-bootstrap/Card';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import { VictoryLine, VictoryChart } from 'victory';
export default function HomeCards(props){
const [activestock, setActiveStock] = useState([])
function handleActiveStocks(props){
if (activestock.includes(props) === false){
setActiveStock([...activestock, props])
console.log(activestock)
}
else {
setActiveStock(activestock.filter(activestock => activestock !== props))
console.log(activestock)
}
}
function Lines(props){
const charts = []
if (props.chart !== undefined){
props.chart.map(function(val, index){
charts.push(
<VictoryLine data={[
{x:index+1, y:index+2},
{x:index+2, y:index+4}
]}/>
)
})
return charts
}
return null
}
function RealCharts(props){
return(
<VictoryChart>
<Lines chart={props.stocks}></Lines>
</VictoryChart>
)
}
function Forms(props){
const hg=[]
props.text.map(function(val, index){
hg.push(
<form>
{val} <input type='checkbox' onClick={()=> handleActiveStocks(val)}/> {index}
</form>
)
})
return(hg)
}
return(
<Container fluid>
<Row style={{position:'relative', top:'2vh'}}>
<Card style={{width:props.width}}>
<Card.Header>U.S Equity</Card.Header>
<Forms
text={['S&P 500', 'NASDAQ',' DOW', 'Russel 1000', 'Large Cap', 'Small Cap', 'MSFT', 'FB']}
/>
</Card>
<Card>
{/* <VictoryChart >
<Lines chart={activestock}/>
</VictoryChart> */}
<RealCharts stocks={activestock}/>
</Card>
</Row>
</Container>
)
}
You need a checked={some_value_here} for checkbox to be checked.
import React, { useState, useEffect } from "react";
import Card from "react-bootstrap/Card";
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import { VictoryLine, VictoryChart } from "victory";
export default function HomeCards(props) {
const [activestock, setActiveStock] = useState([]);
function handleActiveStocks(props) {
if (activestock.includes(props) === false) {
setActiveStock([...activestock, props]);
console.log(activestock);
} else {
setActiveStock(activestock.filter(activestock => activestock !== props));
console.log(activestock);
}
}
function Lines(props) {
const charts = [];
if (props.chart !== undefined) {
props.chart.map(function(val, index) {
charts.push(
<VictoryLine
data={[
{ x: index + 1, y: index + 2 },
{ x: index + 2, y: index + 4 }
]}
/>
);
});
return charts;
}
return null;
}
function RealCharts(props) {
return (
<VictoryChart>
<Lines chart={props.stocks} />
</VictoryChart>
);
}
// useEffect()
function Forms(props) {
const hg = [];
props.text.map(function(val, index) {
console.log(activestock)
// check the value exists in the activeStock
const checked=activestock.includes(val);
hg.push(
<form>
{val}{" "}
<input type="checkbox" checked={checked} onClick={() => handleActiveStocks(val)} />{" "}
{index}
</form>
);
});
return hg;
}
return (
<Container fluid>
<Row style={{ position: "relative", top: "2vh" }}>
<Card style={{ width: props.width }}>
<Card.Header>U.S Equity</Card.Header>
<Forms
text={[
"S&P 500",
"NASDAQ",
" DOW",
"Russel 1000",
"Large Cap",
"Small Cap",
"MSFT",
"FB"
]}
/>
</Card>
<Card>
{/* <VictoryChart >
<Lines chart={activestock}/>
</VictoryChart> */}
<RealCharts stocks={activestock} />
</Card>
</Row>
</Container>
);
}
The shared state is not wrong, you just need to add necessary check before return it.

How do I delete a card component using id from a data object?

I have built a Trello clone using ReactJS, where I have 4 columns called TODO, DOING, DONE and REJECTED, where I can add a card to any column.
In a file I am trying to map over card component and rendering properties from defined dummy data.
What I want to do?
I want to delete a specific card when it is clicked using the card id in some way.
What is the problem?
I do not understand how do I delete an entire card object when it matches a certain id.
My TaskboardList.js component :
import React from "react";
import TaskboardCard from "./TaskboardCard";
import TaskboardActionButton from "./TaskboardActionButton";
import { Droppable } from "react-beautiful-dnd";
const TaskboardList = ({ title, cards, listID }) => {
return (
<Droppable droppableId={String(listID)}>
{provided => (
<div
className="taskboardlist_container"
{...provided.droppableProps}
ref={provided.innerRef}
style={styles.container}
>
<div className="sub-heading">{title}</div>
{cards.map((card, index) => (
<TaskboardCard
key={card.id}
index={index}
text={card.text}
id={card.id}
/>
))}
<TaskboardActionButton listID={listID} />
{provided.placeholder}
</div>
)}
</Droppable>
);
};
const styles = {
container: {
backgroundColor: "#eee",
width: 300,
padding: "0.5rem",
marginRight: "1rem",
height: "100%"
}
};
export default TaskboardList;
My TaskboardCard.js component
import React from "react";
import Card from "#material-ui/core/Card";
import Typography from "#material-ui/core/Typography";
import CardContent from "#material-ui/core/CardContent";
import { Draggable } from "react-beautiful-dnd";
const TaskboardCard = ({ text, id, index, sample }) => {
return (
<Draggable draggableId={String(id)} index={index}>
{provided => (
<div
className="taskboard_container"
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<Card>
<CardContent>
<Typography style={{ fontSize: "1.5rem" }} gutterBottom>
{text}
</Typography>
</CardContent>
</Card>
</div>
)}
</Draggable>
);
};
export default TaskboardCard;
For further reference to more files, I am attaching my GitHub link. Please consider visiting.
Any help would be much appreciated.
https://github.com/abhinav-anshul/consensolabs
And here is the link for a live demo https://consensolab.abhinavanshul.com/
// src/actions/index.js
export const CONSTANTS = {
ADD_CARD: "ADD_CARD",
ADD_LIST: "ADD_LIST",
DRAG_HAPPENED: "DRAG_HAPPENED",
DELETE_CARD: "DELETE_CARD"
};
// src/actions/cardActions.js
export const deleteCard = cardId => ({
type: CONSTANTS.DELETE_CARD,
payload: { cardId }
});
// src/reducers/listReducers.js
const listReducer = (state = initialState, action) => {
// ...
case CONSTANTS.DELETE_CARD: {
return {
...state,
cards: state.cards.filter(({id}) => id !== action.payload.cardId)
}
}
Then from your delete button, you just need to call dispatch(deleteCard(cardId))
Edit: I've updated your code sandbox to implement this https://codesandbox.io/s/stupefied-golick-7z78k

how to search filter with pagination best practice reactjs?

I have a problem if on page 1 and after (except 2) what I search (type) if there is data it will display the data that I search (type), see the picture below:
the problem is if on page 2, what I search for will appear on another page. even though on page 2 the data is there, :
This is page 2 before searching :
and this is page 1 before searching
if I'm on page 2 there is data that appears abc and dcs. if I search for dcs then dcs appear or if I type d it will appear d and if on other pages there is also data it will display
I use this codesanbox.io url:
https: //codesandbox.io/embed/condescending-pine-d7q3v
and this my code:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import dummyQnA from "./dummyQnA.json";
import "./styles.css";
import { Row, Col, Pagination, Button, Table, Divider } from "antd";
import Search from "antd/lib/input/Search";
import "antd/dist/antd.css";
const columns = [
{
title: "Question",
dataIndex: "questionAndAnswer",
key: "questionAndAnswer"
}
];
class App extends Component {
constructor(props) {
super(props);
this.state = {
search: ""
};
}
getHighlightedText(text, higlight) {
if (!higlight.trim()) {
return <span>{text}</span>;
}
let parts = text.split(new RegExp(`(${higlight})`, "gi"));
return (
<span>
{parts
.filter(part => part)
.map((part, i) => (
<mark
key={i}
style={
part.toLowerCase() === higlight.toLowerCase()
? { backgroundColor: "yellow" }
: {}
}
>
{part}
</mark>
))}
</span>
);
}
renderQnA = (qna, i) => {
return {
key: i,
questionAndAnswer: [
<Col key={i} md={24} style={{ marginTop: 20 }}>
<Row>
<Col md={23}>
<b>
{" "}
{this.getHighlightedText(qna.questionAdmin, this.state.search)}
</b>
<p style={{ color: "#417505" }}>
{" "}
{this.getHighlightedText(qna.answerCustomer, this.state.search)}
</p>
</Col>
</Row>
</Col>
]
};
};
onChange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const lowercasedFilter = search.toLowerCase();
const filteredQnA = dummyQnA.filter(item => {
return Object.keys(item).some(key =>
item[key].toLowerCase().includes(lowercasedFilter)
);
});
return (
<div className="product-forum">
<Row className="title-inline">
<Col md={13} style={{ paddingTop: "6px" }}>
<span className="title-inline__title">
Pertanyaan terkait Produk ({dummyQnA.length})
</span>
</Col>
<Col md={3}>
<Button
type="link"
className="title-inline__button-live-chat"
onClick={this.handleLiveChat}
>
LIVE CHAT
</Button>
</Col>
<Col md={8}>
<Search
value={this.state.search}
placeholder="Cari pertanyaan terkait"
onChange={this.onChange}
/>
</Col>
</Row>
<Table
className="table-qna"
showHeader={false}
pagination={{ defaultPageSize: 5 }}
dataSource={filteredQnA.map((QnA, i) => this.renderQnA(QnA, i))}
columns={columns}
/>
<Divider />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Categories

Resources