react避免子组件渲染
Here’s a common scenario in React: You’re mapping over an array, and you need each item to call a click handler and pass some relevant data.
这是React中的一个常见场景:您正在数组上进行映射,并且需要每个项目来调用单击处理程序并传递一些相关数据。
Here’s an example. I’m iterating over a list of users and passing the userId to delete to the deleteUser function on line 31.
这是一个例子。 我正在遍历用户列表,并将要删除的userId传递给第31行的deleteUser函数。
import React from 'react';
class App extends React.Component {
constructor() {
this.state = {
users: [
{ id: 1, name: 'Cory' },
{ id: 2, name: 'Meg' }
]
};
}
deleteUser = id => {
this.setState(prevState => {
return { users: prevState.users.filter( user => user.id !== id)}
})
}
render() {
return (
<div>
<h1>Users</h1>
<ul>
{
this.state.users.map( user => {
return (
<li key={user.id}>
<input
type="button"
value="Delete"
onClick={() => this.deleteUser(user.id)}
/>
{user.name}
</li>
)
})
}
</ul>
</div>
);
}
}
export default App;
Here’s a working example on Codesandbox. (which is awesome ?)
这是Codesandbox上的工作示例 。 (太棒了?)
所以有什么问题? (So What’s the Problem?)
I’m using an arrow function in the click handler. This means every time render runs, a new function is allocated. In many cases, this isn’t a big deal. But if you have child components, they’ll re-render even when data hasn’t changed because each render allocates a new function.
我在点击处理程序中使用了箭头功能。 这意味着每次渲染运行时,都会分配一个新函数 。 在许多情况下,这并不是什么大问题。 但是,如果您有子组件,则即使数据未更改,它们也会重新渲染,因为每个渲染都分配了一个新功能。
Bottom line: Avoid declaring arrow functions or binding in render for optimal performance. My team uses this ESLint rule to help alert us to this issue.
底线 :避免在渲染中声明箭头功能或绑定以获得最佳性能。 我的团队使用此ESLint规则来帮助提醒我们该问题。
有什么解决方案? (What’s the Solution?)
So how do you avoid binding and arrow functions in render? One option is to extract a child component. Here, I’ve extracted the list item to UserListItem.js:
那么如何避免在render中使用绑定和箭头功能呢? 一种选择是提取子组件。 在这里,我将列表项提取到UserListItem.js:
import React from 'react';
import PropTypes from 'prop-types';
class UserListItem extends React.Component {
onDeleteClick = () => {
// No bind needed since we can compose
// the relevant data for this item here
this.props.onClick(this.props.user.id);
}
// No arrow func in render! ?
render() {
return (
<li>
<input
type="button"
value="Delete"
onClick={this.onDeleteClick}
/>
{this.props.user.name}
</li>
);
}
}
UserListItem.propTypes = {
user: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired
};
export default UserListItem;
Then, the parent component’s render gets simpler, and no longer needs to contain an arrow function. It passes the relevant context for each list item down via props in the new “renderUserListItem” function.
然后,父组件的渲染变得更简单,不再需要包含箭头功能。 它通过新的“ renderUserListItem”函数中的道具向下传递每个列表项的相关上下文。
import React from 'react';
import { render } from 'react-dom';
import UserListItem from './UserListItem';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [{ id: 1, name: 'Cory' }, { id: 2, name: 'Sherry' }],
};
}
deleteUser = id => {
this.setState(prevState => {
return { users: prevState.users.filter(user => user.id !== id) };
});
};
renderUserListItem = user =>
<UserListItem key={user.id} user={user} onClick={this.deleteUser} />;
render() {
return (
<div>
<h1>Users</h1>
<ul>
{this.state.users.map(this.renderUserListItem)}
</ul>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Note that instead of using an arrow function in render while mapping, we’re calling a new function declared outside of render on line 19. No more function allocations on each render. ?
请注意,我们在映射时未在渲染时使用箭头函数,而是在第19行的render外部调用了一个声明的新函数。不再在每个渲染上分配函数。 ?
Here’s a working example of this final refactor.
是或否? (Yay or Yuck?)
This pattern improves performance by eliminating redundant function allocations. So it’s most useful when this situation applies to your component:
此模式通过消除冗余功能分配来提高性能。 因此,当这种情况适用于您的组件时,它是最有用的:
- Render is called frequently. 渲染经常被调用。
- Rendering children is expensive. 渲染孩子很昂贵。
Admittedly, extracting a child component as I’ve suggested above is extra work too. It requires more moving parts, and more code. So if you’re not having performance issues, it’s arguably a premature optimization ?.
诚然,按照我上面的建议提取子组件也是额外的工作。 它需要更多的活动部件和更多的代码。 因此,如果您没有性能问题,那可以说是过早的优化?
So you have two options: Either allow arrows and binds everywhere (and deal with perf issues if they pop up), or forbid them for optimal performance and consistency.
因此,您有两种选择:要么允许箭头并在任何地方进行绑定(并在出现问题时处理性能问题),要么禁止它们获得最佳性能和一致性。
Bottom-line: I recommend disallowing arrows and binds in render. Here’s why:
底线:建议不要在渲染中使用箭头和绑定。 原因如下:
You have to disable the useful ESLint rule I suggested above to allow it.
您必须禁用上面建议的有用的ESLint规则以允许它。
- Once you disable a linting rule, people are likely to copy this pattern and start disabling other linting rules. An exception in one place can quickly become the norm… 禁用掉毛规则后,人们很可能会复制此模式并开始禁用其他掉毛规则。 一个地方的例外情况很快就会成为常态……
So I find extracting child components a useful pattern to avoid binding in render.
因此,我发现提取子组件是避免在渲染中绑定的有用模式。
Have another way you like to handle this? Chime in via the comments!
您还有另一种处理方式吗? 通过评论鸣叫!
寻找更多关于React的信息? ⚛ (Looking for More on React? ⚛)
I’ve authored multiple React and JavaScript courses on Pluralsight (free trial). My latest, “Creating Reusable React Components” just published! ?
我已经在Pluralsight上编写了多个React和JavaScript课程 ( 免费试用 )。 我的最新作品“ 创建可重用的React组件 ”刚刚发布! ?
Cory House is the author of multiple courses on JavaScript, React, clean code, .NET, and more on Pluralsight. He is principal consultant at reactjsconsulting.com, a Software Architect at VinSolutions, a Microsoft MVP, and trains software developers internationally on software practices like front-end development and clean coding. Cory tweets about JavaScript and front-end development on Twitter as @housecor.
Cory House是JavaScript,React,干净代码,.NET等课程的多本课程的作者,并且还提供了有关Pluralsight的更多课程 。 他是reactjsconsulting.com的首席顾问, VinSolutions的软件架构师,Microsoft MVP,并且在软件开发方面对国际软件开发人员进行了培训,例如前端开发和简洁编码。 Cory在Twitter上以@housecor表示关于JavaScript和前端开发的推文 。
react避免子组件渲染