I am trying to filter the cards here according to the City Name. And I think the problem is that I cannot access the state of Child Component within the Parent Component and I cannot seem to resolve the issue
import { React, useState, useEffect } from "react";
import {Container, Row, Col} from 'react-bootstrap';
import DestCard from "./Card";
import { StyledLink } from "./Home.styled";
import { getCities } from "./api";
import Navbar from "./NavBar"
import ImageCarousel from "./ImageCarousel"
import Grid from '@mui/material/Unstable_Grid2';
import FilterComponent from "./FilterComponent";
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import { Button } from "react-bootstrap";
function Home() {
const [cities, setCities] = useState(getCities());
const [filteringcities, setFilteringCities]= useState(getCities());
// useEffect(()=>{
// setCities(cities);
// },[]);
// function filterCities()
// {
// let sortedStudents = cities.sort((a, b) => {
// if (a.title < b.title) {
// return -1;
// }
// if (a.title > b.title) {
// return 1;
// }
// return 0;
// });
// setCities(
// sortedStudents
// )
// }
function linkto(){
let sortedStudents = cities.sort((a, b) => {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});
setCities(
sortedStudents
)
}
return (
<div>
<Navbar />
<ImageCarousel style={{ width: "100%", height: "500px" }} />
<FilterComponent onClick={linkto}></FilterComponent>
{/* <Button variant="outline-dark" onClick={filterCities}>City Name</Button> */}
<Grid2 container spacing={{ xs: 2 }} columns={{ xs: 4, md: 16 }} style={{marginLeft:"20px", marginTop:"30px"}}>
{cities.map((details, index) => (
<Grid2 item xs={2} sm={4} md={4} key={index}>
<StyledLink to={`/city/${details.title}`}>
<DestCard details= {details} />
</StyledLink>
</Grid2>
))}
</Grid2>
</div>
)
}
export default Home;
Here is my Parent or Home Component and I Have the child Component FilterComponent which is an ‘OffCanvas’ React Bootstrap Component.
import React, {useEffect, useState} from "react";
import Button from 'react-bootstrap/Button';
import Offcanvas from 'react-bootstrap/Offcanvas';
import { StyledButton } from "./FilterComponent.styled";
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import { getCities } from "./api";
import { StyledLink } from "./Home.styled";
import DestCard from "./Card.jsx";
const options = [
{
name: 'Filters',
scroll: true,
backdrop: true,
},
];
function OffCanvasExample({ name, linkto, ...props}) {
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const toggleShow = () => setShow((s) => !s);
// const [filteringcities, setFilteringCities]= useState(getCities());
// useEffect(()=>{
// setFilteringCities(filterCities);
// },[]);
// function filterCities()
// {
// let sortedStudents = filteringcities.sort((a, b) => {
// if (a.title < b.title) {
// return -1;
// }
// if (a.title > b.title) {
// return 1;
// }
// return 0;
// });
// console.log(sortedStudents);
// setFilteringCities(
// // <Grid2 container spacing={{ xs: 2 }} columns={{ xs: 4, md: 16 }} style={{marginLeft:"20px", marginTop:"30px"}}>
// // {sortedStudents.map((details, index) => (
// // <Grid2 item xs={2} sm={4} md={4} key={index}>
// // <StyledLink to={`/city/${details.title}`}>
// // <DestCard details= {details} />
// // </StyledLink>
// // </Grid2>
// // ))}
// // </Grid2>
// sortedStudents
// )
// }
return (
<>
<StyledButton variant="primary" onClick={toggleShow} className="me-2">
{name}
</StyledButton>
<Offcanvas show={show} onHide={handleClose} {...props}>
<Offcanvas.Header closeButton>
<Offcanvas.Title>Filters</Offcanvas.Title>
</Offcanvas.Header>
<hr></hr>
<Offcanvas.Body>
<Grid2 container spacing={2} columns={{ xs: 4, md: 16}}>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark" onClick={linkto}>City Name</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
<Grid2 xs={2} sm={4} md={4}>
<Button variant="outline-dark">Dark</Button>
</Grid2>
</Grid2>
</Offcanvas.Body>
</Offcanvas>
</>
);
}
function FilterComponent({linkto}) {
return (
<>
{/* <button onClick={ ()=> {handleChange("no")}}></button> */}
{options.map((props, idx) => (
<OffCanvasExample key={idx} func={linkto} {...props} />
))}
</>
);
}
export default FilterComponent;
Above is my FilterComponent. I need to build functionality such that when I click my ‘City Name’ Button I should render all the cards in Home lexicographically according to City Name.
I know that we have to pass callback from parent to do that but I can’t actually figure out how.
Above is my Filter Button
Above is my Actual Button on which I want to add the functionality
Any help would be appreciated.
Edit:
I referred to this link React component not re-rendering on state change and the problem was that React was not re-rendering the Cards because it was not recognizing that the state was changing. Updated Code of Home is below.
function linkto(){
let sortedCities= [...cities];
sortedCities = sortedCities.sort((a, b) => {
if (a.title < b.title) {
return -1;
}
if (a.title > b.title) {
return 1;
}
return 0;
});
// console.log(sortedCities);
setCities(sortedCities)
}
2
Answers
You say filter, but looks more like sorting, since I don’t see any input field where user types in to "filter" out city names. In your code
let sortedStudents = cities.sort((a, b) =>
, you are directly mutating the statecities
, which is bad practice in react so change that to something likelet copiedCities = cities
then do the sorting. Instead performing this sorting in Parent component, you may want to perform it inFilterComponent
orSortComponent
which I think you should rename it to. You’ll passcities
state to child component(SortComponent) then do the sorting in there.You are passing callback
linkto
to Filtercomponent atHome
After that you need to correctly destructure it
And then in
Offcanvas