'What is the best way to render a search bar component that takes in a props in another component using react v6
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
Solution 1:[1]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Drew Reese |
