JSX props'larında neden satır içi ok işlevlerini kullanmamalısınız?
Ok işlevlerini kullanmak veya JSX'te bağlamayı kullanmak, performansa zarar veren kötü bir uygulamadır çünkü işlev her işlemede yeniden oluşturulur.
Bir işlev oluşturulduğunda, önceki işlev çöp olarak toplanır. Birçok öğeyi yeniden işlemek, animasyonlarda şaka yaratabilir.
Bir satır içi ok işlevinin PureComponent
kullanılması shallowCompare
, shouldComponentUpdate
yöntemde kullanılan e-postaların ve bileşenlerin yine de yeniden oluşturulmasına neden olur . Ok fonksiyonu pervanesi her seferinde yeniden oluşturulduğundan, yüzeysel karşılaştırma bunu bir pervane için bir değişiklik olarak tanımlayacak ve bileşen yeniden oluşturulacaktır.
Aşağıdaki 2 örnekte görebileceğiniz gibi - satır içi ok işlevini kullandığımızda, <Button>
bileşen her seferinde yeniden oluşturulur (konsol 'oluşturma düğmesi' metnini gösterir).
Örnek 1 - PureComponent olmadan içi işleyicisi
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
onClick = () => this.setState((prevState) => ({
counter: prevState.counter + 1
}));
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ this.onClick } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Örnek 2 - PureComponent ile içi işleyicisi
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ () => this.setState((prevState) => ({
counter: prevState.counter + 1
})) } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
this
Ok işlevlerini satır içi olmadan bağlama yöntemleri
Yöntemi yapıcıda el ile bağlama:
class Button extends React.Component {
constructor(props, context) {
super(props, context);
this.cb = this.cb.bind(this);
}
cb() {
}
render() {
return (
<button onClick={ this.cb }>Click</button>
);
}
}
Ok işlevi ile öneri sınıfı alanlarını kullanarak bir yöntemi bağlama . Bu bir 3. aşama önerisi olduğundan, babel yapılandırmanıza Aşama 3 ön ayarını veya Sınıf özellikleri dönüşümünü eklemeniz gerekir .
class Button extends React.Component {
cb = () => { // the class property is initialized with an arrow function that binds this to the class
}
render() {
return (
<button onClick={ this.cb }>Click</button>
);
}
}
İç geri aramalara sahip İşlev Bileşenleri
Bir işlev bileşeninin içinde bir iç işlev (örneğin olay işleyicisi) oluşturduğumuzda, işlev bileşen her oluşturulduğunda yeniden oluşturulacaktır. İşlev, bir alt bileşene ( Button
bu durumda) props olarak (veya bağlam aracılığıyla) aktarılırsa , bu çocuk da yeniden oluşturacaktır.
Örnek 1 - İç geri aramalı İşlev Bileşeni:
const { memo, useState } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
<button onClick={onClick}>Click</button>
));
const Parent = () => {
const [counter, setCounter] = useState(0);
const increment = () => setCounter(counter => counter + 1); // the function is recreated all the time
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
Bu sorunu çözmek için geri aramayı kancaya sarabilirizuseCallback()
ve bağımlılıkları boş bir diziye ayarlayabiliriz.
Not:useState
oluşturulan işlevi mevcut durumunu sağlayan bir güncelleme fonksiyonu, kabul eder. Bu şekilde, mevcut durumu için bir bağımlılık ayarlamamıza gerek kalmaz useCallback
.
Örnek 2 - useCallback ile sarmalanmış bir iç geri aramaya sahip İşlev Bileşeni:
const { memo, useState, useCallback } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
<button onClick={onClick}>Click</button>
));
const Parent = () => {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => setCounter(counter => counter + 1), []);
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>