I am taking input from a search input field using searchInput and setSearchInput useState hook and after I press submit button, I call fetchSearchData function providing it the input text and setCompanies hook, where companies are updated with the fetched list of companies from the API.
Then companies are passed to another component CompanyList where a map function is called there.
The problem is whenever I type in the search field, the CompanyList component is re-rendered although I did not press submit. I understand that setSearchInput will re-render SearchBar component whenever I type in it, but I don't get why CompanyList re-renders.
Search page source code:
const Search = () => {
const [companies, setCompanies]=useState([]); //List of companies returned from searching
const [searchInput, setSearchInput] = useState(""); //Search field input
//Update search text whenever the user types in
const onSearchChange = (e) => {
setSearchInput(e.target.value)
}
//use the API providing it the search input, and
//setCompanies hook to update list of companies
const onSearchSubmit = (e) => {
e.preventDefault()
fetchSearchData(searchInput, setCompanies)
}
return (
<div>
<Container>
<Row className={"searchFilterBar"}>
<Col sm={6} md={8} className={"searchBar"}>
<SearchBar onSubmit={onSearchSubmit} onChange={onSearchChange} value={searchInput} />
</Col>
<Col sm={6} md={4} className={"filterBar"}>
</Col>
</Row>
<CompanyList companies={companies} ></CompanyList>
<Row>
</Row>
</Container>
</div>
)
}
export default Search;
SearchBar component source code:
const SearchBar = ({value,onSubmit, onChange}) => {
return (
<Form
className="search-form"
onSubmit={onSubmit}
>
<div className="input-group">
<span className="input-group-text rubik-font">
<i className="icon ion-search"></i>
</span>
<input
className="form-control rubik-font"
type="text"
placeholder="Search for companies that start with..."
onChange={onChange}
value={value}
/>
<Button className="btn btn-light rubik-font" type="submit">Search </Button>
</div>
</Form>
)
}
CompanyList component source code:
function MapDataToCompanyList(response) {
console.log(response); //Logging occurs here
if(!response || response===undefined || response.length===0)
{
return (<ErrorBoundary message={noCompaniesError.message}></ErrorBoundary>)
}
return response.map((company) => {
return (
<Col key={company._id} xs={12} md={6} lg={4} className="mt-2">
<CompanyCard
id={company._id}
logo={company.logo}
title={company.name}
logoBackground={company.logoBackground}
progLangs={company.progLangs}
backend={company.backend}
frontend={company.frontend}
url={company.url}
>
</CompanyCard>
</Col>
)
})
}
const CompanyList = (props) => {
const {companies} = props
return (
<div>
<Container className="mt-3">
<Row>
{
MapDataToCompanyList(companies)
}
</Row>
</Container>
</div>
)
}
export default CompanyList;
FetchSearchData function source code:
export const fetchSearchData = (query, cb)=>{
const uri = process.env.NODE_ENV === 'development' ?
`http://localhost:3000/api/companies/name/${query}` :
``;
axios.get(uri, {
timeout: MAX_TIMEOUT
})
.then((response)=>{
cb(response.data.data)
})
.catch((error)=>{
console.log(error)
})
}
As seen above, empty list of companies is logged when the page first loads, then I typed three characters and the it logged three time which means the map function called three times.
Even then if I pressed submit and retrieved list of companies normally, whenever I type it will keep printing the array of companies that was fetched.
Sorry if I missed something, I am still new to React.


CompanyListwill be infact re-rendereder, you could use auseEffectwith empty deps list like:useEffect(() => { console.log("CompanyList rendering"); });