原文转自https://zhuanlan.zhihu.com/p/29266705
在 render 中使用箭头函数或绑定会导致子组件重新渲染,即使 state 并没有改变。作者推荐使用提取子组件或在 HTML 元素中传递数据的方式来避免绑定。
En este ejemplo, utilizo una función de flecha en el renderizado para vincular el ID de usuario a cada botón de eliminación.
Haga clic en CodeSandbox para ver y demostrar la demostración completa. (CodeSandbox es genial. Es un editor en línea de React que puede compilar y mostrar la interfaz actual en tiempo real).
import React from 'react';
import { render } from 'react-dom';
import User from './User';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{ id: 1, name: 'Cory' },
{ id: 2, name: 'Meg' },
{ id: 3, name: 'Bob' }
]
};
}
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 <User
key={user.id}
name={user.name}
onDeleteClick={() => this.deleteUser(user.id)} />
})
}
</ul>
</div>
);
}
}
export default App;
render(<App />, document.getElementById('root'));
En la línea 35, estoy usando una función de flecha para pasar un valor a la función eliminarUsuario, y ahí es donde radica el problema.
Para ver por qué es así, veamos primero User.js:
import React from 'react';
// Note how the debugger below gets hit when *any* delete
// button is clicked. Why? Because the parent component
// uses an arrow function, which means this component
//
class User extends React.PureComponent {
render() {
const {name, onDeleteClick } = this.props
console.log(`${name} just rendered`);
return (
<li>
<input
type="button"
value="Delete"
onClick={onDeleteClick}
/>
{name}
</li>
);
}
}
export default User;
Cada vez que se llama a render, se imprime un registro en la consola. El usuario ha sido declarado como PureComponent. Por lo tanto, el usuario solo debe volver a renderizar cuando cambien los accesorios o el estado. Sin embargo, cuando hace clic en el botón Eliminar, se llamará a render para cada instancia de Usuario .
La razón es: el componente principal pasa una función de flecha en los accesorios. Las funciones de flecha se reasignan cada vez que se representan (de la misma manera que se usa bind) . Entonces, aunque declaré Usuario como PureComponent, la función de flecha en el componente principal del Usuario hace que el componente Usuario pase una nueva función a todas las instancias de Usuario. Entonces, cuando se hace clic en cualquier botón de eliminación, se volverán a representar todas las instancias de usuario.
en conclusión:
Evite el uso de funciones de flecha y enlaces en el renderizado. De lo contrario, se interrumpirá la optimización del rendimiento de mustComponentUpdate y PureComponent.
¿Lo que debe hacerse?
Primero veamos un ejemplo para comparar la diferencia de no usar funciones de flecha en el renderizado.
Haga clic en CodeSandbox para ver y ejecutar la demostración completa.
import React from 'react';
import { render } from 'react-dom';
import User from './User';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{ id: 1, name: 'Cory' },
{ id: 2, name: 'Meg' },
{ id: 3, name: 'Bob'}
],
};
}
deleteUser = id => {
this.setState(prevState => {
return {
users: prevState.users.filter(user => user.id !== id)
};
});
};
renderUser = user => {
return <User key={user.id} user={user} onClick={
this.deleteUser} />;
}
render() {
return (
<div>
<h1>Users</h1>
<ul>
{
this.state.users.map(this.renderUser)}
</ul>
</div>
);
}
}
render(<App />, document.getElementById('root'));
En este ejemplo, no hay funciones de flecha en la representación de index.js. Los datos relevantes se pasan a User.js:
import React from "react";
import PropTypes from "prop-types";
// Note that the console.log below isn't called
// when delete is clicked on a user.
// That's because pureComponent's shallow
// comparison works properly here because
// the parent component isn't passing down
// an arrow function (which would cause this
// component to see a new function on each render)
class User extends React.PureComponent {
onDeleteClick = () => {
// No bind needed since we can compose the relevant data for this item here
this.props.onClick(this.props.user.id);
};
render() {
console.log(`${name} just rendered`);
return (
<li>
<input
type="button"
value="Delete"
onClick={
this.onDeleteClick}
/>
{
this.props.user.name}
</li>
);
}
}
User.propTypes = {
user: PropTypes.object.isRequired,
onClick: PropTypes.func.isRequired
};
export default User;
En User.js, onDeleteClick llama a la función onClick pasada en accesorios y pasa el user.id correspondiente.
Cuando vuelvas a hacer clic en el botón Eliminar, ¡otros usuarios nunca volverán a llamar a render!
Resumir
Para un mejor rendimiento:
- Evite el uso de funciones de flecha y enlaces en el renderizado.
- ¿Cómo hacerlo? Extraiga componentes secundarios o pase datos directamente a elementos HTML
- Consulte No.bind() o las funciones de flecha en JSX Props (react/jsx-no-bind) para agregar
eslint
detección de pares.bind方法和箭头函数
y soluciones.