skip to Main Content

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.

This is my Filter Button

Above is my Filter Button

enter image description here

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


  1. 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 state cities, which is bad practice in react so change that to something like let copiedCities = cities then do the sorting. Instead performing this sorting in Parent component, you may want to perform it in FilterComponent or SortComponent which I think you should rename it to. You’ll pass cities state to child component(SortComponent) then do the sorting in there.

    Login or Signup to reply.
  2. You are passing callback linkto to Filtercomponent at Home

     <FilterComponent onClick={linkto} {...props}></FilterComponent>
    

    After that you need to correctly destructure it

    function FilterComponent({onClick, ...others}) {
        return (
            <>
                {/* <button onClick={ ()=> {handleChange("no")}}></button> */}
                {options.map((props, idx) => (
                    <OffCanvasExample key={idx} func={onClick} {...others} />
                ))}
            </>
        );
    }
    

    And then in Offcanvas

    function OffCanvasExample({ name, func, ...props}) {
        const [show, setShow] = useState(false);
        const handleClose = () => setShow(false);
        const toggleShow = () => setShow((s) => !s);
    
        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>
            </>
        );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search