Reputation: 35
I have my search component that is supposed to be passed into a header component but the tutorial I am using is old and was using an older version of react.
This is my Search.js component.
import React, { useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
const Search = ({ history }) => {
const [keyword, setKeyword] = useState('');
const searchHandler = (e) => {
e.preventDefault()
if (keyword.trim()) {
history.push(`/search/${keyword}`)
} else {
history.push('/')
}
}
console.log('my keyword', keyword);
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
And this is how I pass it into my Header.js component
import React, { Fragment } from 'react'
import { Route, Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { useAlert } from 'react-alert'
import { logout } from '../../actions/userActions'
import Search from './Search'
import '../../App.css'
const Header = () => {
return (
<Fragment>
<nav className="navbar row">
<div className="col-12 col-md-6 mt-2 mt-md-0">
<Route render={({ history }) => <Search history={history} />} />
</div>
</nav>
</Fragment>
)
}
export default Header
Whenever I run the code it tells me I need to wrap it in a <Routes>
I did it like this
<Routes>
<Route render={({ history }) => <Search history={history} />} />
</Routes>
But when I wrap it like this it doesn't give any errors but the search bar doesn't show at all in my browser header
What is the correct way to render this please?
I also read that the history.push
in my search.js has been replaced by a useNavigate
so I tried changing that to make my Search.js look like this
import React, { useState } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
const Search = ({ }) => {
const [keyword, setKeyword] = useState('');
const navigate = useNavigate();
const searchHandler = (e) => {
e.preventDefault()
if (keyword.trim()) {
navigate(`/search/${keyword}`)
} else {
navigate('/search')
}
}
console.log('my keyword', keyword);
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
But I have no idea how to render it properly in my Header
component
Upvotes: 3
Views: 2191
Reputation: 203257
From what I can tell you are using react-router-dom
v6, so your last snippet of the Search
component using the useNavigate
hook is correct.
const Search = () => {
const [keyword, setKeyword] = useState("");
const navigate = useNavigate();
const searchHandler = (e) => {
e.preventDefault();
if (keyword.trim()) {
navigate(`/search/${keyword}`);
} else {
navigate("/search");
}
};
console.log("my keyword", keyword);
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>
);
};
But the issue is that you are trying to render it on a Route
using the older RRDv5 Route
APIs.
<Route render={({ history }) => <Search history={history} />} />
In v6 gone are the component
, and render
and children
function props. Gone also are the route props, i.e. history
, location
, and match
, this is why you need the useNavigate
hook to get the navigate
function in Search
.
From what I can tell, Search
was only rendered by a Route
in the old tutorial simply to have the history
object passed in as a prop. I don't see any reason for it to be rendered by a Route
. Just render Search
directly in the Header
.
const Header = () => {
return (
<nav className="navbar row">
<div className="col-12 col-md-6 mt-2 mt-md-0">
<Search />
</div>
</nav>
);
};
Assuming the Header
component is rendered within a routing context provided by a router (BrowserRouter
, HashRouter
, MemoryRouter
, etc...) the useNavigate
hook will work.
Upvotes: 2