Contents

วิธีใช้ปุ่มตอบสนองเพื่อหลีกเลี่ยงความขัดแย้งของส่วนประกอบ

เฟรมเวิร์ก 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 เช่น เว็บแอปพลิเคชัน ยังได้รับประโยชน์จากกลยุทธ์การปรับให้เหมาะสมต่างๆ อาจใช้เทคนิคการปรับปรุงประสิทธิภาพที่หลากหลายเพื่อปรับปรุงการทำงานและประสบการณ์ของผู้ใช้