Je comprends que les fonctions flèches rendent les choses plus efficaces en évitant de en ne recréant pas les fonctions à chaque fois qu'elles sont utilisées.
C'est pas vrai .
Les fonctions de la flèche gèrent les this
le contexte d'une manière lexicale, là où une fonction "normale" le fait dynamiquement . J'ai écrit sur ce mot clé en profondeur si vous avez besoin de plus d'informations à ce sujet.
Dans vos deux exemples de la fonction flèche en ligne, vous créez une nouvelle instance de la fonction sur chaque render
.
Ceci créera et passera une nouvelle instance à chaque rendu.
onClick={() => {}}
Dans le troisième exemple, vous n'avez qu'une seule instance.
Ceci ne fait que passer une référence à une instance déjà existante
onClick={this.myHandler}
Quant aux avantages des fonctions de flèches en tant que champs de classe (il y a une petit bémol (je l'afficherai en bas de la réponse), si vous avez un gestionnaire de fonction normal qui a besoin d'accéder à l'instance actuelle de la fonction class
via this
:
myHandler(){
// this.setState(...)
}
Vous devrez expliciter bind
à la class
.
L'approche la plus courante consistera à le faire dans la section constructor
car il ne fonctionne qu'une seule fois :
constructor(props){
super(props);
this.myHandler = this.myHandler.bind(this);
}
Si vous utilisez une fonction flèche en tant que gestionnaire, vous n'avez pas besoin de bind
à la class
car comme mentionné ci-dessus, la fonction flèche utilise un contexte lexical pour this
:
myHandler = () => {
// this.setState(...)
}
Dans les deux cas, vous utiliserez le gestionnaire de la manière suivante :
<div onClick={this.myHandler}></div>
La principale raison de cette approche :
<div onClick={() => this.myHandler(someParameter)}></div>
C'est si vous voulez passer des paramètres au gestionnaire en plus de la fonction native event
qui sont passés, ce qui signifie que vous voulez passer un paramètre vers le haut.
Comme mentionné, cela créera une nouvelle instance de fonction à chaque rendu.
(Il existe une meilleure approche pour cela, continuez à lire).
Exemple de fonctionnement pour un tel cas d'utilisation :
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
}
}
toggleITem = (itemName) => {
this.setState(prev => {
const nextState = prev.items.map(item => {
if (item.name !== itemName) return item;
return {
...item,
active: !item.active
}
});
return { items: nextState };
});
}
render() {
const { items } = this.state;
return (
<div>
{
items.map(item => {
const style = { color: item.active ? 'green' : 'red' };
return (
<div
onClick={() => this.toggleITem(item.name)}
style={style}
>
{item.name}
</div>
)})
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Une meilleure approche consisterait à créer une composition de composants.
Vous pouvez créer un composant enfant qui englobe le balisage pertinent, qui aura son propre gestionnaire et qui obtiendra à la fois l'adresse de l'utilisateur et celle de l'utilisateur. data
et handler
comme des accessoires du parent.
Le composant enfant invoquera alors le gestionnaire qu'il a obtenu du parent et transmettra le paramètre data
en tant que paramètre.
Exemple de fonctionnement avec le composant enfant :
class Item extends React.Component {
onClick = () => {
const { onClick, name } = this.props;
onClick(name);
}
render() {
const { name, active } = this.props;
const style = { color: active ? 'green' : 'red' };
return (<div style={style} onClick={this.onClick}>{name}</div>)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
}
}
toggleITem = (itemName) => {
this.setState(prev => {
const nextState = prev.items.map(item => {
if (item.name !== itemName) return item;
return {
...item,
active: !item.active
}
});
return { items: nextState };
});
}
render() {
const { items } = this.state;
return (
<div>
{
items.map(item => {
return <Item {...item} onClick={this.toggleITem} />
})
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Les champs de la classe côté négatif :
Comme je l'ai mentionné, il y a un petit inconvénient pour les champs de classe.
La différence entre une méthode de classe et un champ de classe est que le champ de classe est attaché à l'élément instance
de la class
(fonction constructeur).
alors que les méthodes et les objets de la classe sont attachés au prototype.
Par conséquent, si vous avez un nombre ridiculement important d'instances de cette classe, vous mai obtenir un coup de performance.
Étant donné ce bloc de code :
class MyClass {
myMethod(){}
myOtherMethod = () => {}
}
babel le transposera en ceci :
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var MyClass = function() {
function MyClass() {
_classCallCheck(this, MyClass);
this.myOtherMethod = function() {};
}
_createClass(MyClass, [{
key: "myMethod",
value: function myMethod() {}
}]);
return MyClass;
}();
0 votes
developer.mozilla.org/fr/US/docs/Web/JavaScript/Référence/ voici plus de détails
0 votes
onClick={this.props.prevItem}
ici puisqu'il n'y a pas de référence àthis
surprevItem
vous pouvez l'utiliser. Mais si vous ajoutez du code au niveau de l'étendue, il se cassera. Puisque vous assignez une fonction d'un objet et l'appelez, elle perd son contexte.3 votes
Pour information, les champs de classe ne font pas partie de l'ES6.
0 votes
Duplicata possible de Comment utiliser les fonctions fléchées (champs publics de classe) comme méthodes de classe ?