เหตุใดคุณจึงไม่ควรใช้ฟังก์ชันลูกศรแบบอินไลน์ในอุปกรณ์ประกอบฉาก JSX
การใช้ฟังก์ชันลูกศรหรือการเชื่อมโยงใน JSX เป็นแนวทางปฏิบัติที่ไม่ดีซึ่งส่งผลเสียต่อประสิทธิภาพเนื่องจากฟังก์ชันถูกสร้างขึ้นใหม่ในการเรนเดอร์แต่ละครั้ง
เมื่อใดก็ตามที่มีการสร้างฟังก์ชันฟังก์ชันก่อนหน้านี้จะถูกเก็บรวบรวมขยะ การแสดงผลองค์ประกอบจำนวนมากอาจทำให้ภาพเคลื่อนไหวติดขัด
การใช้ฟังก์ชันลูกศรอินไลน์จะทำให้เกิดPureComponent
s และส่วนประกอบที่ใช้shallowCompare
ในshouldComponentUpdate
วิธีการแสดงผลต่อไป เนื่องจากฟังก์ชันลูกศรถูกสร้างขึ้นใหม่ทุกครั้งการเปรียบเทียบแบบตื้นจะระบุว่าเป็นการเปลี่ยนแปลงของเสาและส่วนประกอบจะแสดงผล
ดังที่คุณเห็นใน 2 ตัวอย่างต่อไปนี้ - เมื่อเราใช้ฟังก์ชันลูกศรอินไลน์<Button>
คอมโพเนนต์จะแสดงผลทุกครั้ง (คอนโซลจะแสดงข้อความ "ปุ่มแสดงผล")
ตัวอย่างที่ 1 - PureComponent ที่ไม่มีตัวจัดการแบบอินไลน์
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>
ตัวอย่างที่ 2 - PureComponent พร้อมตัวจัดการแบบอินไลน์
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
โดยไม่มีฟังก์ชันลูกศร inlining
การผูกวิธีด้วยตนเองในตัวสร้าง:
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>
);
}
}
การผูกเมธอดโดยใช้ข้อเสนอคลาสฟิลด์ด้วยฟังก์ชันลูกศร เนื่องจากนี่เป็นข้อเสนอขั้นที่ 3 คุณจะต้องเพิ่มค่าที่ตั้งไว้ล่วงหน้าขั้นที่ 3หรือคุณสมบัติของคลาสจะเปลี่ยนเป็นการกำหนดค่า babel ของคุณ
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>
);
}
}
ส่วนประกอบของฟังก์ชันที่มีการเรียกกลับภายใน
เมื่อเราสร้างฟังก์ชันภายใน (ตัวจัดการเหตุการณ์เป็นต้น) ภายในองค์ประกอบของฟังก์ชันฟังก์ชันจะถูกสร้างขึ้นใหม่ทุกครั้งที่แสดงผลส่วนประกอบ หากฟังก์ชันถูกส่งผ่านเป็นอุปกรณ์ประกอบฉาก (หรือผ่านบริบท) ไปยังองค์ประกอบลูก ( Button
ในกรณีนี้) เด็กคนนั้นจะแสดงผลอีกครั้งด้วย
ตัวอย่างที่ 1 - ส่วนประกอบของฟังก์ชันที่มีการเรียกกลับภายใน:
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>
ในการแก้ปัญหานี้เราสามารถตัดการเรียกกลับด้วยuseCallback()
hookและตั้งค่าการอ้างอิงเป็นอาร์เรย์ว่าง
หมายเหตุ:useState
ฟังก์ชั่นที่สร้างยอมรับฟังก์ชั่นอัพเดทที่ให้สถานะปัจจุบัน useCallback
ด้วยวิธีนี้เราไม่จำเป็นต้องตั้งค่าสถานะปัจจุบันของการพึ่งพา
ตัวอย่างที่ 2 - ส่วนประกอบของฟังก์ชันที่มีการเรียกกลับด้านในห่อด้วย useCallback:
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>