1

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>
);
nt369
  • 57
  • 1
  • 10
  • React router dom has a useLocation hook to get URL params. https://reactrouter.com/web/api/Hooks/uselocation I guess this should trigger on search params change too. You can checkout the syntax to get search params here: https://stackoverflow.com/a/68098291/4290781 – Deep Oct 10 '21 at 09:28

2 Answers2

2

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}
      />
   )}
/>
noiseymur
  • 761
  • 2
  • 15
  • where exactly in the router can i add this? – nt369 Oct 10 '21 at 09:42
  • 1
    Inside the Switch component where you define your routes. – noiseymur Oct 10 '21 at 09:46
  • @nt369 have you tried this answer? please give the feedback. – nima Oct 11 '21 at 10:37
  • i have a mapping functions which maps through all components and give them key values. i inserted the history object but it doesent seem to change anything. link is getting updated but the component doesent reload. i will try to set state and work with state to reload – nt369 Oct 12 '21 at 11:37
1

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.

nima
  • 7,796
  • 12
  • 36
  • 53