Dont render Search component with Router React js

Viewed 86

With react-router-dom, I can't render my Search component, which I created, into the main Header component.

I think problem is in this line <Route render={({ history }) => } />

but don't know what to do for two days now...

I'm trying to implement a search on the website but I'm stuck

Please help :D

Header.js

import React, { Fragment } from 'react';
import { Route, Routes } from 'react-router-dom';

import Search from './Search';

import '../../App.css';

const Header = () => {
  return (
    <Fragment>
      <nav className='navbar row'>
        <div className='col-12 col-md-3'>
          <div className='navbar-brand'>
            <img src='/images/shopit_logo.png' alt='Site logo' />
          </div>
        </div>

        <div className='col-12 col-md-6 mt-2 mt-md-0'>
          <Routes>
            <Route render={({ history }) => <Search history={history} />} />
          </Routes>
        </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.js

mport 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;

//App.js

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

import Header from './components/layout/Header';
import Footer from './components/layout/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;

1 Answers

Issue

You are correct, cause of the issue is:

<Routes>
  <Route render={({ history }) => <Search history={history} />} />
</Routes>

In react-router-dom v6 the Route components no longer have component, or render or children function props. There also no longer exists the old route props. RRDv6 also doesn't expose out the history object and instead uses a navigate function.

Solution

Since Search is a function component you can just import and use the useNavigate hook and replace the history.push with navigate.

Header.js

<div className='col-12 col-md-6 mt-2 mt-md-0'>
  <Search />
</div>

Search.js

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';

const Search = () => {
  const navigate = useNavigate();
  const [keyword, setKeyword] = useState('');

  const searchHandler = (e) => {
    e.preventDefault();

    if (keyword.trim()) {
      navigate(`/search/${keyword}`);
    } else {
      navigate('/');
    }
  };

  return (
    <form onSubmit={searchHandler}>
      ...
    </form>
  );
};
Related