Home > Mobile >  Keep URL and state when working with filter drop-downs using react hook
Keep URL and state when working with filter drop-downs using react hook

Time:10-11

I'm new to react and hooks, I'm trying to achieve a filter where the last selected filter option would set the value on my drop down toggle but at the same time change the URL when a filter is selected.

My problem is I can only do one or the other but not both. Here's my filter drop down component:

import React, { useState } from 'react'
import { Dropdown } from  'react-bootstrap';
 
function FilterDropDown ({onFilterChange}) {

    const handleSelect=(e)=>{
    console.log(e);
  }

     const onDropDownChange = (dropDownValue) => setGenreDropDown(dropDownValue);
        const [genreDropDown, setGenreDropDown] = useState('')


    return (
    <Dropdown className="text-center m-3 p-auto">
    <Dropdown.Toggle variant="success" id="dropdown-basic">
        {genreDropDown}
    </Dropdown.Toggle>

    <Dropdown.Menu>
        <Dropdown.Item href="#/Genre/Action" onClick={() => { onFilterChange("Action"); onDropDownChange("Action");}}>Action</Dropdown.Item>
        <Dropdown.Item href="#/Genre/Adventure" onClick={() => { onFilterChange("Adventure"); onDropDownChange("Adventure");}}>Adventure</Dropdown.Item>
        <Dropdown.Item href="#/Genre/Role-Playing" onClick={() => { onFilterChange("Role-Playing"); onDropDownChange("Role-Playing");}}>Role-Playing</Dropdown.Item>
    </Dropdown.Menu>
    </Dropdown>
        )
}

export default FilterDropDown

and here's my App:

import React, { useState } from 'react';
import Navi from './Navi'
import CardGroup from './CardGroup'
import SearchBox from './SearchBox'
import './App.css';
import games from './csvjson.json';
import Content from './Content';
import FilterDropDown from './FilterDropDown'
// import Search from './search';
import {
  HashRouter as Router,
  Route,
    useLocation
} from "react-router-dom";



function App()  {
  const [searchfield, setSearchfield] = useState('')
  const [filterField, setFilterField] = useState('')


const onSearchChange = (event) => {
  setSearchfield(event.target.value)
  // event.preventDefault();
  }


const onFilterChange = (filterGenre) => setFilterField(filterGenre);


        const filteredGames = games.filter(game => {
        return (game.Title.toLowerCase().includes(searchfield.toLowerCase()) && game.genre.toLowerCase().includes(filterField.toLowerCase()))
        })

        return (
          <Router>
            <Route path="/" exact render={props => 
                <div>
                <Navi />
                <SearchBox searchChange={onSearchChange}/>
                <FilterDropDown onFilterChange={onFilterChange} />
                <CardGroup games={filteredGames}/>
                </div> }/>
            <Route path="/games/:games" component={Content} />

            {console.log("/" `${filterField}`)}
            <Route path={"/Genre/" `${filterField}`} render={props => 
              <div>
                <Navi />
                <SearchBox searchChange={onSearchChange}/>
                <FilterDropDown onFilterChange={onFilterChange}/>
                <CardGroup games={filteredGames}/>
                </div> }
                />
          </Router>
        );
  }

 
export default App;

CodePudding user response:

You need to have genereDropDown state inside your parent component and pass down it with its state changing function onDropDownChange to the child component FilterDropDown as follows.

import React, { useState } from "react";
import Navi from "./Navi";
import CardGroup from "./CardGroup";
import SearchBox from "./SearchBox";
import "./App.css";
import games from "./csvjson.json";
import Content from "./Content";
import FilterDropDown from "./FilterDropDown";
// import Search from './search';
import { HashRouter as Router, Route, useLocation } from "react-router-dom";

function App() {
  const [searchfield, setSearchfield] = useState("");
  const [filterField, setFilterField] = useState("");

  const [genreDropDown, setGenreDropDown] = useState("");
  const onDropDownChange = (dropDownValue) => setGenreDropDown(dropDownValue);

  const onSearchChange = (event) => {
    setSearchfield(event.target.value);
    // event.preventDefault();
  };

  const onFilterChange = (filterGenre) => setFilterField(filterGenre);

  const filteredGames = games.filter((game) => {
    return (
      game.Title.toLowerCase().includes(searchfield.toLowerCase()) &&
      game.genre.toLowerCase().includes(filterField.toLowerCase())
    );
  });

  return (
    <Router>
      <Route
        path="/"
        exact
        render={(props) => (
          <div>
            <Navi />
            <SearchBox searchChange={onSearchChange} />
            <FilterDropDown onFilterChange={onFilterChange} />
            <CardGroup games={filteredGames} />
          </div>
        )}
      />
      <Route path="/games/:games" component={Content} />

      {console.log("/"   `${filterField}`)}
      <Route
        path={"/Genre/"   `${filterField}`}
        render={(props) => (
          <div>
            <Navi />
            <SearchBox searchChange={onSearchChange} />
            <FilterDropDown
              onFilterChange={onFilterChange}
              genreDropDown={genreDropDown}
              onDropDownChange={onDropDownChange}
            />
            <CardGroup games={filteredGames} />
          </div>
        )}
      />
    </Router>
  );
}

export default App;

Then use them inside the child component as follows.

import React from "react";
import { Dropdown } from "react-bootstrap";

function FilterDropDown({ onFilterChange, genreDropDown, onDropDownChange }) {
  const handleSelect = (e) => {
    console.log(e);
  };

  return (
    <Dropdown className="text-center m-3 p-auto">
      <Dropdown.Toggle variant="success" id="dropdown-basic">
        {genreDropDown}
      </Dropdown.Toggle>

      <Dropdown.Menu>
        <Dropdown.Item
          href="#/Genre/Action"
          onClick={() => {
            onFilterChange("Action");
            onDropDownChange("Action");
          }}
        >
          Action
        </Dropdown.Item>
        <Dropdown.Item
          href="#/Genre/Adventure"
          onClick={() => {
            onFilterChange("Adventure");
            onDropDownChange("Adventure");
          }}
        >
          Adventure
        </Dropdown.Item>
        <Dropdown.Item
          href="#/Genre/Role-Playing"
          onClick={() => {
            onFilterChange("Role-Playing");
            onDropDownChange("Role-Playing");
          }}
        >
          Role-Playing
        </Dropdown.Item>
      </Dropdown.Menu>
    </Dropdown>
  );
}

export default FilterDropDown;

Hope this would solve your issue.

  • Related