I am building a listing page where products are displayed and i have a search window in my header (on every page).
The search window works fine. I enter a searchword, it forwards to the listing page and it gives me the results. This works on every site, except when i am already on the listing page. If i enter a searchword while i am on the listing page, it changes the url, but nothing else.
Code Search: The Searchinput triggers the change and is a component inside Search and looks as follows:
import React, { useState, useRef } from 'react';
import { LISTING_POSTS_PAGE } from 'settings/constant';
import { HOME_PAGE } from 'settings/constant';
const SearchInput = ({history}) => {
const [searchword, setSearchword] = useState('');
const submitHandler = (e) => {
e.preventDefault();
history.search= '?' searchword;
history.push({
pathname: LISTING_POSTS_PAGE,
})
}
return (
<form className="search" onSubmit={submitHandler}>
<div className = "row">
<input
type = "text"
searchword = "q"
id = "q"
placeholder = "What do you want to buy?"
onChange = {(e) => setSearchword(e.target.value)}>
</input>
</div>
</form>
);
};
const Search= (props) => {
console.log(props)
const { updatevalue } = props;
return <SearchInput getinputvalue={updatevalue} history={props.history} />;
};
export default Search;
The listing page looks like this and takes the history object to make an api request to my db before rendering.
import React, { useState, Fragment } from 'react';
import Sticky from 'react-stickynode';
import Toolbar from 'components/UI/Toolbar/Toolbar';
import { Checkbox } from 'antd';
import CategotySearch from 'components/Search/CategorySearch/CategotySearch';
import { PostPlaceholder } from 'components/UI/ContentLoader/ContentLoader';
import SectionGrid from 'components/SectionGrid/SectionGrid';
import ListingMap from './ListingMap';
import FilterDrawer from 'components/Search/MobileSearchView';
import useWindowSize from 'library/hooks/useWindowSize';
import useDataApi from 'library/hooks/useDataApi';
import { SINGLE_POST_PAGE } from 'settings/constant';
import ListingWrapper, { PostsWrapper, ShowMapCheckbox } from './Listing.style';
export default function Listing({ location, history }) {
let url = 'http://127.0.0.1:5000/api/products'
if (history.search) {
url = url history.search;
}
console.log(url)
const { width } = useWindowSize();
const [showMap, setShowMap] = useState(false);
const { data, loading, loadMoreData, total, limit } = useDataApi(url);
let columnWidth = [1 / 1, 1 / 2, 1 / 3, 1 / 4, 1 / 5];
if (showMap) {
columnWidth = [1 / 1, 1 / 2, 1 / 2, 1 / 2, 1 / 3];
}
const handleMapToggle = () => {
setShowMap((showMap) => !showMap);
};
return (
<ListingWrapper>
<Sticky top={82} innerZ={999} activeClass="isHeaderSticky">
<Toolbar
left={
width > 991 ? (
<CategotySearch history={history} location={location} />
) : (
<FilterDrawer history={history} location={location} />
)
}
right={
<ShowMapCheckbox>
<Checkbox defaultChecked={false} onChange={handleMapToggle}>
Show map
</Checkbox>
</ShowMapCheckbox>
}
/>
</Sticky>
<Fragment>
<PostsWrapper className={width > 767 && showMap ? 'col-12' : 'col-24'}>
<SectionGrid
link={SINGLE_POST_PAGE}
columnWidth={columnWidth}
data={data}
totalItem={total.length}
loading={loading}
limit={limit}
handleLoadMore={loadMoreData}
placeholder={<PostPlaceholder />}
/>
</PostsWrapper>
{showMap && <ListingMap />}
</Fragment>
</ListingWrapper>
);
}
I tried to pass down the history object so i do not use different history objects (like useHistory from "react-router-dom") but it didnt changed anything on that behaviour.
I Do assume this is because i try to do history.push(LISTING_PAGE) while i am already on this page. But as far i read, this should be irrelevant. What do you think?
EDIT: My index.js lloks as follows:
const App = () => (
<ThemeProvider theme={theme}>
<>
<GlobalStyles />
<BrowserRouter>
<AuthProvider>
<Routes />
</AuthProvider>
</BrowserRouter>
</>
</ThemeProvider>
);
CodePudding user response:
You need to add a hidden Link
element in your SearchInput
component. also need to create a reference and pass it to the Link
element to trigger the click action on it:
import React, {useRef} from 'react';
import {Link} from 'react-router-dom';
// rest of the codes ...
// inside of SearchInput component
const linkRef = useRef(null);
return (
<form className="search" onSubmit={submitHandler}>
<div className = "row">
<Link to={LISTING_POSTS_PAGE} className={{display: "none"}} ref={linkRef} />
// rest of the codes ...
Now, it's time to change the submitHandler
method to trigger a click action on the Link
element after submitting the form:
const submitHandler = (e) => {
e.preventDefault();
history.search= '?' searchword;
linkRef.current.click() // ---> instead of using history.push()
}
Note: better solution may be available, like force page to re-render and so on but using a simple concept of Link
will be helpful as I explained above.
CodePudding user response:
React re-renders the page when a key of the component is changed. So you can do this in your router. This will make sure the key is change every time a param updates, thus result in re-render of the component.
<Route
exact
path="/your-page/:param"
render={(props) => (
<YourComponent
key={props.match.params.prodId}
/>
)}
/>