I Am Making A Search Functionality On My Website But Whenever I Type Something And Hit The Search Button The Address ( URL ) Changes But The Component Stays The Same And When I Refresh The Page After That The Component Appears On The Screen.
Here's A Picture Of What I Meant :
URL CHANGES BUT COMPONENT IS SAME
Here's A Picture After The Reload :
Should Be Like This When I Hit The Search
There Was A Solution I Found That Changing From Browser Router To Router Works But That Seems To Give The Following Error :
Uncaught TypeError: Cannot read properties of undefined (reading 'pathname')
App.js
import "./App.css";
import {
BrowserRouter as Router,
Route,
Switch,
Routes,
} from "react-router-dom";
import Header from "./Components/Layouts/Header";
import Footer from "./Components/Layouts/Footer";
import Home from "./Components/Home";
import ProductDetails from "./Components/Product/ProductDetails";
function App() {
return (
<Router>
<div className="App">
<Header />
<div className="container container-fluid">
<Routes>
<Route path="/" element={<Home />} exact />
<Route path="/search/:keyword" element={<Home />} />
<Route path="/product/:id" element={<ProductDetails />} />
</Routes>
</div>
<Footer />
</div>
</Router>
);
}
export default App;
History.js
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
Header Component
import React, { Fragment } from "react";
import { Route } from "react-router-dom";
import history from "./history";
import Search from "./Search";
const Header = () => {
return (
<Fragment>
<nav className="navbar row">
<div className="col-12 col-md-3">
<div className="navbar-brand">
<img src="./images/logo.png" />
</div>
</div>
<div className="col-12 col-md-6 mt-2 mt-md-0">
<Search history={history} />
</div>
<div className="col-12 col-md-3 mt-4 mt-md-0 text-center">
<button className="btn" id="login_btn">
Login
</button>
<span id="cart" className="ml-3">
Cart
</span>
<span className="ml-1" id="cart_count">
2
</span>
</div>
</nav>
</Fragment>
);
};
export default Header;
Search Component
import React, { useState } from "react";
const Search = ({ history }) => {
const [keyword, setKeyword] = useState("");
const searchHandler = (e) => {
e.preventDefault();
if (keyword.trim()) {
history.push(`/search/${keyword}`);
} else {
history.push("/");
}
};
return (
<form onSubmit={searchHandler}>
<div className="input-group">
<input
type="text"
id="search_field"
className="form-control"
placeholder="Enter Product Name ..."
onChange={(e) => setKeyword(e.target.value)}
/>
<div className="input-group-append">
<button id="search_btn" className="btn">
<i className="fa fa-search" aria-hidden="true"></i>
</button>
</div>
</div>
</form>
);
};
export default Search;
Home Component
import React, { Fragment, useState } from "react";
import { useParams } from "react-router-dom";
import Pagination from "react-js-pagination";
import MetaData from "./Layouts/MetaData";
import { useDispatch, useSelector } from "react-redux";
import { getAllProducts } from "../Actions/productActions";
import { useEffect } from "react";
import Product from "./Product/Product";
import Loader from "./Layouts/Loader";
import { useAlert } from "react-alert";
const Home = () => {
const [currentPage, setCurrentPage] = useState(1);
const dispatch = useDispatch();
const alert = useAlert();
const { loading, products, error, productsCount, resultPerPage } =
useSelector((state) => state.products);
const { keyword } = useParams();
useEffect(() => {
if (error) {
return alert.error(error);
}
dispatch(getAllProducts(keyword, currentPage));
}, [dispatch, error, alert, keyword, currentPage]);
function setCurrentPageNo(pageNumber) {
setCurrentPage(pageNumber);
}
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title="Buy At Discount Price" />
<h1 id="products_heading">Latest Products</h1>
<section id="products" className="container mt-5">
<div className="row">
{products &&
products.map((product) => (
<Product product={product} key={product._id} />
))}
</div>
</section>
{resultPerPage <= productsCount && (
<div className="d-flex justify-content-center mt-5">
<Pagination
activePage={currentPage}
itemsCountPerPage={resultPerPage}
totalItemsCount={productsCount}
onChange={setCurrentPageNo}
nextPageText={"Next"}
prevPageText={"Prev"}
firstPageText={"First"}
lastPageText={"Last"}
itemClass="page-item"
linkClass="page-link"
/>
</div>
)}
</Fragment>
)}
</Fragment>
);
};
export default Home;
Action
import axios from "axios";
import {
ALL_PRODUCTS_REQUEST,
ALL_PRODUCTS_SUCESS,
ALL_PRODUCTS_FAIL,
PRODUCT_DETAILS_REQUEST,
PRODUCT_DETAILS_SUCCESS,
PRODUCT_DETAILS_FAIL,
CLEAR_ERRORS,
} from "../Constants/productConstants";
// Get All Product ( ACTIONS )
export const getAllProducts =
(keyword = "", currentPage = 1) =>
async (dispatch) => {
try {
dispatch({ type: ALL_PRODUCTS_REQUEST });
const { data } = await axios.get(
`/api/v1/products?keyword=${keyword}&page=${currentPage}`
);
dispatch({
type: ALL_PRODUCTS_SUCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ALL_PRODUCTS_FAIL,
payload: error.response.data.message,
});
}
};
// Product Details ( ACTIONS )
export const getProductDetails = (id) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST });
const { data } = await axios.get(`/api/v1/product/${id}`);
dispatch({
type: PRODUCT_DETAILS_SUCCESS,
payload: data.product,
});
} catch (error) {
dispatch({
type: PRODUCT_DETAILS_FAIL,
payload: error.response.data.message,
});
}
};
// Clearing eroor message
export const clearErrors = () => async (dispatch) => {
dispatch({ type: CLEAR_ERRORS });
};
CodePudding user response:
You can try to use the useNavigate() hook instead of createBrowserHistory()
First import useNavigate
import { useNavigate } from 'react-router-dom';
then just do this after importing
const navigate = useNavigate();
const searchHandler = (e) => {
e.preventDefault();
if (keyword.trim()) {
navigate(`/search/${keyword}`);
} else {
navigate("/");
}
};