1

I am using BrowserRouter and history.push to navigate between pages. I want to traverse to a new page with query parameters entered in the first page.

i.e., in the homepage, there is a search bar where user enters some search string abc, and when the button is clicked, I want to redirect to another page /search?q=abc

What I observed is, the /search?q=abc is rendered properly once and then it automatically redirects to /search? dropping all the query parameters. I am not able to understand why is it rendering twice?

Packages

"react": "^16.12.0",
"react-bootstrap": "^1.0.0-beta.16",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2",

App.js

import React, { Component}  from 'react';
import './App.css';
import {BrowserRouter as Router, Route} from 'react-router-dom';
import Jumbotron from "./component/Jumbotron";

const SearchPage = ({ match, location }) => {
  return (
      <p>
        <strong>Query Params: </strong>
        {location.search}
      </p>
  );
};

const HomePage = () => {
  return (
      <div className="d-flex flex-column">
        <div className="container-fluid">
          <Jumbotron/>
        </div>
      </div>
  )
};

class App extends Component {
  render() {
    return (
        <Router>
          <Route exact={true} path='/' render={HomePage}/>
          <Route exact path="/search" render={SearchPage} />
        </Router>
    );
  }
}

export default App;

Jumbotron.jsx <- this is the first page containing search bar

import React, { Component } from 'react';
import { withRouter } from 'react-router';
import history from "../utils/history";

class Jumbotron extends Component {

    handleSubmit = () => {
        history.push({
            pathname: '/search',
            search: '?q=' + this.state.query
        })
    };

    handleChange = e => {
        this.setState({query: e.target.value});
        console.log(e.target.value)
    };

    render() {
        return (<>
            <div className="d-flex jumbotron">
                <div className="align-self-center container mx-auto">
                    <br/>
                    <div>

                    </div>
                    <div className="align-self-center">
                        <form className="d-flex justify-content-center form-inline my-2 my-lg-0">
                            <input className="search-input col-md-6  mb-3 form-control"
                                   type="search"
                                   placeholder="Type the address here"
                                   aria-label="Search"
                                   onChange={this.handleChange}
                            />
                            <button className="search-btn col-md-1 mb-3 btn btn-primary"
                                    onClick={this.handleSubmit}>Search
                            </button>

                        </form>
                    </div>
                </div>
            </div>
            </>
        )
    }
}

export default withRouter(Jumbotron);

history.js

import { createBrowserHistory } from "history";
export default createBrowserHistory();

What am I missing here?

UPDATE

Here is an example with the above code that depicts the behavior: https://codesandbox.io/s/blissful-fermat-60xzy

3
  • Please create a working example, using codesandbox.io for instance Commented Apr 19, 2020 at 0:57
  • @Dekel Added a link to an example. If you see in the sandbox, I can directly open a link https://60xzy.csb.app/search?q=aaa and that shows me the query params, but if I search the query params through the form field, it doesnt work. Commented Apr 19, 2020 at 1:40
  • 1
    I got this to work by wrapping your Jumbotron component in a withRouter and changing the history.push() to a this.props.history.push Commented Apr 19, 2020 at 4:48

1 Answer 1

3

2 ways to solve your issue:

First solution:

  • import Router not BrowserRouter
  • pass your history that you have defined in ./history.js to the Router. Like this <Router history={history}>
  • Now history.push({..... should work as you expected.

Second solution:

  • import BrowserRouter
  • wrap the Jumbotron component with withRouter
  • use this.props.history.push(...) instead of history.push(...)

Working copy of your code(1st solution) is here:

https://codesandbox.io/s/router-issue-page-refresh-after-search-hl849?file=/src/App.js

Sign up to request clarification or add additional context in comments.

2 Comments

I also figured out the first approach. Just wondering, what is the recommended way here ? does BrowserRouter give something more than Router?
Custom history will provide you the flexibility of using history anywhere in your app be it components or general functions ..... With BrowserRouter , you will get history from prop out of the box which will be available to the route-components defined under the browser router. So the recommended way depends on your usecase. In many cases BrowserRouter would suffice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.