Home > Enterprise >  history.push() does not work on the same page using react
history.push() does not work on the same page using react

Time:10-10

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}
      />
   )}
/>
  • Related