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.