[英]More than needed React components re-rendering when typing in input
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.我正在使用
searchInput
和setSearchInput
useState 钩子从搜索输入字段中获取输入,在按下提交按钮后,我调用fetchSearchData
function 为其提供输入文本和setCompanies
钩子,其中companies
使用从 API 获取的公司列表进行更新。
Then companies
are passed to another component CompanyList
where a map function is called there.然后将
companies
传递给另一个组件CompanyList
,在那里调用 map function。
The problem is whenever I type in the search field, the CompanyList
component is re-rendered although I did not press submit.问题是每当我在搜索字段中键入时,
CompanyList
组件都会重新呈现,尽管我没有按提交。 I understand that setSearchInput
will re-render SearchBar
component whenever I type in it, but I don't get why CompanyList
re-renders.我知道
setSearchInput
将在我输入时重新呈现SearchBar
组件,但我不明白为什么CompanyList
会重新呈现。
Search
page source code: Search
页面源代码:
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: SearchBar
组件源码:
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: CompanyList
组件源码:
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: FetchSearchData
function 源代码:
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.如上所示,首次加载页面时会记录空公司列表,然后我输入了三个字符,它记录了三次,这意味着 map function 被调用了三次。
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.抱歉,如果我错过了什么,我还是 React 的新手。
I don't get why CompanyList re-renders.
我不明白为什么 CompanyList 会重新渲染。
Because it's nested in your Search component, and it's not React.memo
'd (or a PureComponent
).因为它嵌套在您的 Search 组件中,而不是
React.memo
(或PureComponent
)。
Yes, the component is updated, but that doesn't mean it necessarily causes a DOM reconciliation.是的,组件已更新,但这并不意味着它一定会导致 DOM 协调。
In any case, React is completely at liberty of calling your component 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 component function (which you shouldn't have in the first place) as performance guidelines.无论如何,React 完全可以随意调用你的组件 function (实际上,在严格模式下,它倾向于每次更新调用它们两次以确保你没有做愚蠢的事情),所以你应该查看组件 function (一开始就不应该有)中的副作用(例如控制台日志记录)作为性能指南。
When you call setSearchInput(e.target.value)
, Search
component will re-render cause its state has changed.当您调用
setSearchInput(e.target.value)
时, Search
组件将重新渲染,因为它的 state 已更改。 Search
component re-renders means every tag nested in it will re-render (except the ones passed via children
). Search
组件重新渲染意味着嵌套在其中的每个标签都将重新渲染(通过children
传递的标签除外)。 That is the normal behaviour of React.这是 React 的正常行为。 If you want to avoid that, you would wanna use
React.memo
for CompanyList
.如果你想避免这种情况,你会想要使用
React.memo
作为CompanyList
。 Or you could use useRef
to bind the input
like so:或者您可以使用
useRef
来绑定input
,如下所示:
const Search = () => {
const [companies, setCompanies] = useState([]); //List of companies returned from searching
const inputRef = React.useRef(null);
//use the API providing it the search input, and
//setCompanies hook to update list of companies
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 companies={companies}></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 companies that start with..."
/>
<Button className="btn btn-light rubik-font" type="submit">
Search
</Button>
</div>
</Form>
);
};
You do not need to maintain a state for input field.您不需要为输入字段维护 state。 You can use
useRef
and pass it to input like below.您可以使用
useRef
并将其传递给输入,如下所示。
<input
ref={inputRef}
className="form-control rubik-font"
type="text"
placeholder="Search for companies that start with..."
/>
And you can get get value inside onSearchSubmit
using inputRef.current.value
您可以使用
onSearchSubmit
在inputRef.current.value
中获取值
This will not re-render you component on input change.这不会在输入更改时重新渲染您的组件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.