admin管理员组文章数量:1315234
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 panies
are updated with the fetched list of panies from the API.
Then panies
are passed to another ponent CompanyList
where a map function is called there.
The problem is whenever I type in the search field, the CompanyList
ponent is re-rendered although I did not press submit. I understand that setSearchInput
will re-render SearchBar
ponent whenever I type in it, but I don't get why CompanyList
re-renders.
Search
page source code:
const Search = () => {
const [panies, setCompanies]=useState([]); //List of panies 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 panies
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 panies={panies} ></CompanyList>
<Row>
</Row>
</Container>
</div>
)
}
export default Search;
SearchBar
ponent 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 panies that start with..."
onChange={onChange}
value={value}
/>
<Button className="btn btn-light rubik-font" type="submit">Search </Button>
</div>
</Form>
)
}
CompanyList
ponent 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((pany) => {
return (
<Col key={pany._id} xs={12} md={6} lg={4} className="mt-2">
<CompanyCard
id={pany._id}
logo={pany.logo}
title={pany.name}
logoBackground={pany.logoBackground}
progLangs={pany.progLangs}
backend={pany.backend}
frontend={pany.frontend}
url={pany.url}
>
</CompanyCard>
</Col>
)
})
}
const CompanyList = (props) => {
const {panies} = props
return (
<div>
<Container className="mt-3">
<Row>
{
MapDataToCompanyList(panies)
}
</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/panies/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 panies 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 panies normally, whenever I type it will keep printing the array of panies that was fetched.
Sorry if I missed something, I am still new to React.
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 panies
are updated with the fetched list of panies from the API.
Then panies
are passed to another ponent CompanyList
where a map function is called there.
The problem is whenever I type in the search field, the CompanyList
ponent is re-rendered although I did not press submit. I understand that setSearchInput
will re-render SearchBar
ponent whenever I type in it, but I don't get why CompanyList
re-renders.
Search
page source code:
const Search = () => {
const [panies, setCompanies]=useState([]); //List of panies 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 panies
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 panies={panies} ></CompanyList>
<Row>
</Row>
</Container>
</div>
)
}
export default Search;
SearchBar
ponent 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 panies that start with..."
onChange={onChange}
value={value}
/>
<Button className="btn btn-light rubik-font" type="submit">Search </Button>
</div>
</Form>
)
}
CompanyList
ponent 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((pany) => {
return (
<Col key={pany._id} xs={12} md={6} lg={4} className="mt-2">
<CompanyCard
id={pany._id}
logo={pany.logo}
title={pany.name}
logoBackground={pany.logoBackground}
progLangs={pany.progLangs}
backend={pany.backend}
frontend={pany.frontend}
url={pany.url}
>
</CompanyCard>
</Col>
)
})
}
const CompanyList = (props) => {
const {panies} = props
return (
<div>
<Container className="mt-3">
<Row>
{
MapDataToCompanyList(panies)
}
</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/panies/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 panies 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 panies normally, whenever I type it will keep printing the array of panies that was fetched.
Sorry if I missed something, I am still new to React.
Share Improve this question edited Feb 21, 2022 at 14:16 Youssouf Oumar 46.3k16 gold badges101 silver badges104 bronze badges asked Feb 21, 2022 at 11:50 miserylordmiserylord 3656 silver badges15 bronze badges 3- Try to add 'e.preventDefault()' in the onChange function – Salah ED Commented Feb 21, 2022 at 12:06
-
You understood why this happens by reading the below answers. Now, if you really want to see how many times
CompanyList
will be infact re-rendereder, you could use auseEffect
with empty deps list like:useEffect(() => { console.log("CompanyList rendering"); });
– Giovanni Esposito Commented Feb 21, 2022 at 12:09 - I'm sure you made a typo, but just pointing out that this is not "empty deps" (onMount) that is "undefined deps" (everyRender) – Phil Commented Sep 4, 2023 at 14:49
3 Answers
Reset to default 4You do not need to maintain a state for input field. You can use useRef
and pass it to input like below.
<input
ref={inputRef}
className="form-control rubik-font"
type="text"
placeholder="Search for panies that start with..."
/>
And you can get get value inside onSearchSubmit
using inputRef.current.value
This will not re-render you ponent on input change.
When you call setSearchInput(e.target.value)
, Search
ponent will re-render cause its state has changed. Search
ponent re-renders means every tag nested in it will re-render (except the ones passed via children
). That is the normal behaviour of React. If you want to avoid that, you would wanna use React.memo
for CompanyList
. Or you could use useRef
to bind the input
like so:
const Search = () => {
const [panies, setCompanies] = useState([]); //List of panies returned from searching
const inputRef = React.useRef(null);
//use the API providing it the search input, and
//setCompanies hook to update list of panies
const onSearchSubmit = (e) => {
e.preventDefault();
fetchSearchData(inputRef.current.value, setCompanies);
inputRef.current.value = "";
};
return (
<div>
<Container>
<Row className={"searchFilterBar"}>
<Col sm={6} md={8} className={"searchBar"}>
<SearchBar inputRef={inputRef} onSubmit={onSearchSubmit} />
</Col>
<Col sm={6} md={4} className={"filterBar"}></Col>
</Row>
<CompanyList panies={panies}></CompanyList>
<Row></Row>
</Container>
</div>
);
};
export default Search;
const SearchBar = ({ onSubmit, inputRef }) => {
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
ref={inputRef}
className="form-control rubik-font"
type="text"
placeholder="Search for panies that start with..."
/>
<Button className="btn btn-light rubik-font" type="submit">
Search
</Button>
</div>
</Form>
);
};
I don't get why CompanyList re-renders.
Because it's nested in your Search ponent, and it's not React.memo
'd (or a PureComponent
).
Yes, the ponent is updated, but that doesn't mean it necessarily causes a DOM reconciliation.
In any case, React is pletely at liberty of calling your ponent function as many times as it likes (and indeed, in Strict Mode it tends to call them twice per update to make sure you're not doing silly things), so you should look at side effects (such as console logging) in your ponent function (which you shouldn't have in the first place) as performance guidelines.
本文标签: javascriptMore than needed React components rerendering when typing in inputStack Overflow
版权声明:本文标题:javascript - More than needed React components re-rendering when typing in input - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741974849a2408057.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论