วิธีใช้ปุ่มตอบสนองเพื่อหลีกเลี่ยงความขัดแย้งของส่วนประกอบ
เฟรมเวิร์ก React อาจนำเสนอความท้าทายที่ซับซ้อน ซึ่งนำไปสู่พฤติกรรมที่ไม่คาดคิดหรือข้อบกพร่องที่เข้าใจยากซึ่งพิสูจน์ได้ยากสำหรับผู้ที่ขาดความเข้าใจในสาเหตุที่แท้จริง
เมื่อแสดงผลส่วนประกอบตามเงื่อนไขตามค่าคุณสมบัติเฉพาะ ความผิดปกติอาจเกิดขึ้นที่เรียกว่าบั๊ก"การแสดงผลตามเงื่อนไขของส่วนประกอบเดียวกัน"หากต้องการเจาะลึกลงไปในปัญหานี้และค้นหาวิธีแก้ไขโดยใช้ปุ่ม React ให้ตรวจสอบปัญหาอย่างใกล้ชิด
ส่วนประกอบของปฏิกิริยาไม่ได้เป็นอิสระเสมอไป
โครงสร้างที่ไม่ซับซ้อนของ React เป็นเหตุผลสำคัญว่าทำไมจึงแนะนำอย่างยิ่งให้ได้รับความเชี่ยวชาญในไลบรารี JavaScript นี้สำหรับการสร้างส่วนต่อประสานผู้ใช้ อย่างไรก็ตาม แม้ว่าการใช้ React จะมีประโยชน์มากมาย แต่สิ่งสำคัญคือต้องยอมรับว่า React มีความไม่สมบูรณ์และบกพร่องอยู่พอสมควร
ปัญหาที่เป็นปัญหาเกิดขึ้นจากสถานการณ์ที่ส่วนประกอบถูกแสดงโดยบังเอิญตามเกณฑ์เฉพาะ แต่ยังมีแอตทริบิวต์ที่ไม่เหมือนกันในระหว่างการอินสแตนซ์
React ใช้ประโยชน์จากอัลกอริทึมการกระจาย DOM เสมือนเพื่ออัปเดตเฉพาะส่วนต่าง ๆ ของ DOM จริงที่มีการเปลี่ยนแปลงตั้งแต่การเรนเดอร์ครั้งก่อนอย่างมีประสิทธิภาพ กลยุทธ์นี้ตั้งอยู่บนสมมติฐานที่ว่าการเปลี่ยนแปลงส่วนใหญ่เกิดขึ้นที่ระดับของแต่ละองค์ประกอบภายในลำดับชั้น มากกว่าที่ระดับบนสุด ดังนั้น เมื่อเปรียบเทียบคอมโพเนนต์พี่น้องที่มีมาร์กอัปเหมือนกันและไม่มีสถานะโลคัล อัลกอริทึมของ React จะจดจำว่าคอมโพเนนต์นั้นเทียบเท่าและข้ามการเรนเดอร์ซ้ำ ดังนั้น สถานะใด ๆ ที่กำหนดไว้ในหนึ่งในองค์ประกอบเหล่านี้จะคงอยู่ในการแสดงผลที่ต่อเนื่องกัน เนื่องจากไม่ได้รับการรีเฟรช
ให้ฉันอธิบายความหมายที่ละเอียดยิ่งขึ้นของข้อความนั้น สมมติว่าเราตรวจสอบตัวอย่างของตารางส่วนประกอบต่อไปนี้:
import { useState, useEffect } from "react"
export function Counter({name}) {
const [count, setCount] = useState(0)
return(
<div>
<div>{name}</div>
<button onClick={() => setCount(c => c-1)}> - </button>
<br />
<button onClick={() => setCount(c => c \+ 1)}> \+ </button>
</div>
)
}
คอมโพเนนต์"Counter"ได้รับคุณสมบัติที่มีชื่อจากเอนทิตีหลักผ่านการแยกโครงสร้างวัตถุ ซึ่งทำหน้าที่เป็นวิธีการรวมคุณสมบัติภายในบริบทของแอปพลิเคชัน React จากนั้นส่วนประกอบจะแสดงการกำหนดนี้ภายในองค์ประกอบ HTML div นอกจากนี้ ยังแสดงองค์ประกอบอินเทอร์เฟซสองรายการ โดยองค์ประกอบหนึ่งออกแบบมาเพื่อลดค่าที่จัดเก็บภายในสถานะ และอีกองค์ประกอบหนึ่งเพื่อเพิ่มค่าดังกล่าว
โค้ดดังกล่าวซึ่งเกี่ยวข้องกับการใช้งานแอปพลิเคชันภายในคอมโพเนนต์"แอป"โดยเฉพาะ ได้ถูกตั้งคำถามเกี่ยวกับปัญหาที่อาจเกิดขึ้น ควรสังเกตว่าไม่มีการทำงานผิดปกติภายในส่วนย่อยของโค้ดที่ให้มา ค่อนข้างจะอยู่ในการใช้ตัวแปร"ตัวนับ"ภายในส่วนประกอบ"แอป"ดังกล่าว
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ? <Counter name="Kingsley"/> : <Counter name="Sally"/> }
<br/>
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
รหัสดังกล่าวโดยเนื้อแท้แล้วจะแสดงการแจงนับที่ขนานนามว่า “คิงสลีย์” ตามค่าเริ่มต้น อย่างไรก็ตาม หากมีใครเพิ่มการนับจำนวนเคาน์เตอร์ดังกล่าวเป็นค่า"ห้า"แล้วแตะที่อุปกรณ์จัดตาราง"สลับ"ในภายหลัง ระบบจะแสดงการแจงนับทางเลือกทันทีในชื่อ"แซลลี่"
อย่างไรก็ตาม ความท้าทายอยู่ที่ความจริงที่ว่าตัวนับไม่กลับสู่สถานะเริ่มต้นที่ศูนย์เมื่อได้รับการจัดเรียงใหม่แล้ว
ปัญหาที่เกิดขึ้นเนื่องจากอินสแตนซ์ส่วนประกอบทั้งสองแสดงชุดองค์ประกอบที่เหมือนกันในลำดับเฉพาะ อย่างไรก็ตาม React ไม่สามารถแยกความแตกต่างระหว่างตัวนับ"Kingsley"และ"Sally"เนื่องจากคุณสมบัติที่ใช้ร่วมกันของพวกเขา นั่นคือแอตทริบิวต์"ชื่อ"น่าเสียดายที่ React ไม่ได้ใช้ความแตกต่างนี้เพื่อระบุความแตกต่างระหว่างส่วนประกอบที่มีค่าคุณสมบัติเทียบเท่ากัน
ทางออกหนึ่งที่เป็นไปได้สำหรับปัญหาตัวนับสองตัวแสดงทับกันคือการปรับเปลี่ยนโครงสร้างของ Document Object Model (DOM) เพื่อสร้างโครงสร้างแบบต้นไม้ที่แตกต่างกันสำหรับตัวนับสองตัว โดยเฉพาะอย่างยิ่ง เราสามารถใส่ตัวนับแรกภายในองค์ประกอบ div และตัวนับที่สองภายในองค์ประกอบส่วน เมื่อทำเช่นนั้น องค์ประกอบทั้งสองจะแสดงผลแยกกัน หลีกเลี่ยงการทับซ้อนกัน อย่างไรก็ตาม การใช้วิธีการดังกล่าวจำเป็นต้องมีความเข้าใจอย่างถ่องแท้เกี่ยวกับ DOM และคุณสมบัติของมัน
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return (
<div>
{ isKingsley ?
(<div>
<Counter name="Kingsley"/>
</div>)
:
(<section>
<Counter name="Sally"/>
</section>)
}
<br />
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
ลักษณะการทำงานของแอปพลิเคชันจะเปลี่ยนไปเมื่อคลิกปุ่ม"Kingsley"และสลับกับองค์ประกอบอื่นในแผนผัง DOM ซึ่งส่งผลให้เกิดการรีเซ็ตสถานะเนื่องจากความแตกต่างระหว่างโครงสร้างของแผนผัง DOM ดั้งเดิมและที่แก้ไข
“ ” ซึ่งส่วนในสุดมีองค์ประกอบเดียว ในทางกลับกัน เมื่อค่า “isKingsley” พลิกกลับระหว่างค่าเท็จและค่าจริง โครงสร้างผลลัพธ์จะเปลี่ยนจาก “ ” เป็น “ ” ซึ่งจะแทนที่แท็กด้านในสุดด้วยแท็กด้านนอกสุดที่ครอบคลุมทั้งองค์ประกอบดั้งเดิมและองค์ประกอบย่อย การแปลงโครงสร้างนี้กระตุ้นให้ React สร้างคอมโพเนนต์ Counter ขึ้นใหม่โดย
อีกทางหนึ่งคือสามารถแก้ไขปัญหานี้ได้โดยไม่ต้องแก้ไขส่วนประกอบโครงสร้างพื้นฐานของโค้ด HTML วิธีการนี้ช่วยลดความต้องการในการปรับการจัดรูปแบบเพื่อให้สามารถแก้ไขปัญหาได้อย่างมีประสิทธิภาพ
การใช้คีย์เพื่อแสดงส่วนประกอบใหม่
เพื่อให้ React แยกความแตกต่างระหว่างส่วนประกอบต่างๆ ระหว่างการเรนเดอร์ มันต้องอาศัยคีย์ ดังนั้น เมื่อนำเสนอส่วนประกอบที่เหมือนกัน จึงจำเป็นต้องกำหนดคีย์ที่แตกต่างกันให้กับแต่ละอินสแตนซ์ เพื่อให้ React ทราบถึงความแตกต่าง
แก้ไขตัวนับแต่ละตัวโดยรวมคีย์เพิ่มเติมดังนี้:
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ?
<Counter key="Kingsley" name="Kingsley"/> :
<Counter key="Sally" name="Sally"/>
}
<br/>
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
เมื่อเพิ่มค่าของตัวนับ"Kingsley"และคลิกที่ปุ่ม"Swap"React จะสร้างตัวอย่างใหม่ของตัวนับและคืนค่าสถานะภายในให้เป็นค่าเริ่มต้นที่ศูนย์
เมื่อเรนเดอร์อาร์เรย์ที่ประกอบด้วยหลายอินสแตนซ์ของประเภทข้อมูลที่เหมือนกันใน React ขอแนะนำให้ใช้คีย์เฉพาะเพื่อแยกความแตกต่างระหว่างกัน นี่เป็นเพราะ React ขาดความสามารถในการแยกแยะองค์ประกอบแต่ละรายการภายในอาร์เรย์ดังกล่าว และการกำหนดตัวระบุที่แตกต่างกันผ่านคีย์ทำให้มั่นใจได้ว่าแต่ละอินสแตนซ์ได้รับการจดจำโดยเฟรมเวิร์ก
export default function App() {
const names = ["Kingsley", "John", "Ahmed"]
return(
<div>
{ names.map((name, index) => {
return <Counter key={index} name={name} />
})}
</div>
)
}
React ใช้โครงสร้างข้อมูลภายในที่เรียกว่า"ตัวนับ"สำหรับแต่ละองค์ประกอบภายในอาร์เรย์ที่กำหนดคีย์ สิ่งนี้ทำให้ระบบสามารถตรวจจับและอัปเดตการแก้ไขใด ๆ ที่เกิดขึ้นกับอาร์เรย์ที่เกี่ยวข้องได้แบบเรียลไทม์
กรณีการใช้งานคีย์ขั้นสูงอื่น
คุณอาจใช้คีย์เพื่อสร้างความสัมพันธ์ระหว่างสององค์ประกอบที่แตกต่างกันตามค่าของตัวแปรสถานะ กล่าวอีกนัยหนึ่ง คุณสามารถเชื่อมต่อส่วนประกอบอินพุตกับส่วนประกอบต่างๆ ที่เปลี่ยนแปลงตามเงื่อนไขของตัวแปรสถานะ
หากต้องการสาธิต ให้ปรับแต่งส่วนประกอบแอป:
import { useState } from "react"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ? <div>Kingsley's Score</div> : <div>Sally's score</div> }
<input key={ isKingsley? "Kingsley" : "Sally" } type="number"/>
<br/>
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
เมื่อใดก็ตามที่ผู้ใช้สลับระหว่างองค์ประกอบ div ที่เกี่ยวข้องกับ Kingsley และ Sally โดยคลิกที่ปุ่ม แอตทริบิวต์คีย์ของอินพุตจะถูกแก้ไขโดยอัตโนมัติจาก"Kingsley"เป็น"Sally"หรือในทางกลับกัน ด้วยเหตุนี้ React จึงต้องการการสร้างองค์ประกอบอินพุตใหม่ทั้งหมดเมื่อกดปุ่มติดต่อกันแต่ละครั้ง
เคล็ดลับเพิ่มเติมสำหรับการเพิ่มประสิทธิภาพแอปพลิเคชันการตอบสนอง
การปรับโค้ดให้เหมาะสมเป็นสิ่งสำคัญสำหรับการมอบประสบการณ์ผู้ใช้ที่สนุกสนานทั้งในแอปพลิเคชันบนเว็บและมือถือ เนื่องจากโค้ดมีบทบาทสำคัญในการรับประกันว่าแอปพลิเคชันจะทำงานได้อย่างราบรื่นและมีประสิทธิภาพ เมื่อทำความคุ้นเคยกับเทคนิคการเพิ่มประสิทธิภาพต่างๆ คุณจะสามารถเพิ่มประสิทธิภาพของแอปพลิเคชันที่ใช้ React และเพิ่มความพึงพอใจโดยรวมของผู้ใช้ได้
แอปพลิเคชันแบบเนทีฟของ React เช่น เว็บแอปพลิเคชัน ยังได้รับประโยชน์จากกลยุทธ์การปรับให้เหมาะสมต่างๆ อาจใช้เทคนิคการปรับปรุงประสิทธิภาพที่หลากหลายเพื่อปรับปรุงการทำงานและประสบการณ์ของผู้ใช้