การเขียนโปรแกรมเมตาด้วย React

Mar 09 2023
จุดประสงค์ไม่ใช่เพื่อลงรายละเอียดเกี่ยวกับ metaprogramming และเทคนิคของมัน แต่เพียงเพื่อดูตัวอย่างวิธีนำไปใช้ใน React นี่เป็นโพสต์แรกของฉันบนสื่อที่ยอดเยี่ยมนี้ และฉันต้องการเขียนเล็กน้อยเกี่ยวกับเทคนิคหนึ่งที่เราใช้กันไปแล้วครั้งหนึ่งในชีวิต (จากโปรแกรมเมอร์) แต่ที่เราอาจไม่รู้ในรายละเอียด นั่นก็คือ metaprogramming! โค้ดด้านล่างเป็นตัวอย่างของวิธีใช้ Proxy build และ Reflect API ภายในส่วนประกอบ React
ภาพถ่ายโดย Lautaro Andreani บน Unsplash

จุดประสงค์ไม่ใช่เพื่อลงรายละเอียดเกี่ยวกับ metaprogramming และเทคนิคของมัน แต่เพียงเพื่อดูตัวอย่างวิธีนำไปใช้ใน React

นี่เป็นโพสต์แรกของฉันบนสื่อที่ยอดเยี่ยมนี้ และฉันต้องการเขียนเกี่ยวกับเทคนิคหนึ่งที่เราเคยใช้มาแล้วครั้งหนึ่งในชีวิต (จากโปรแกรมเมอร์) แต่ที่เราอาจไม่รู้ในรายละเอียด นั่นก็คือmetaprogramming !

โค้ดด้านล่างเป็นตัวอย่างของวิธีใช้Proxy build และReflect API ภายในส่วนประกอบ React คอมโพเนนต์MyComponentใช้สถานะในเครื่องของ React ( useState ) เพื่อจัดการ วัตถุ proxyDataที่มีคุณสมบัติ " test " ที่ว่างเปล่าในตอนแรก คอมโพเนนต์มีปุ่มสามปุ่มที่เมื่อคลิก จะแก้ไขคุณสมบัติ "ทดสอบ" ของอ็อบเจ็กต์proxyData

import React, { useState } from 'react';

function MyComponent() {
  const [proxyData, setProxyData] = useState({ test: '' });
  const [render, setRender] = useState(false);

  const handleClickMemo = React.useCallback(() => {
    const updatedData = new Proxy(proxyData, {
      set(target, prop, value) {
        const success = Reflect.set(target, prop, value);
        if (success) {
          console.log(`Prop ${prop} modified with value ${value}`);
        }
        return success;
      },
    });
    updatedData.test = crypto.randomUUID();
    setProxyData(updatedData);
  }, []);

  // without useCallback, do new proxy every time
  const handleClick = () => {
    const updatedData = new Proxy(proxyData, {
      set(target, prop, value) {
        const success = Reflect.set(target, prop, value);
        if (success) {
          console.warn(`Prop ${prop} modified with value ${value}`);
        }
        return success;
      },
    });
    updatedData.test = crypto.randomUUID();
    setProxyData(updatedData);
  };

  // case where react doesn't render, but in console,
  // if it is a proxy the object is updated
  // BE CAREFUL when using proxies
  const handleClickNoRender = () => {
    proxyData.test = crypto.randomUUID();
    setProxyData(proxyData);
  };

  return (
    <div>
      <pre>{JSON.stringify(proxyData)}</pre>
      <button onClick={handleClickMemo}>handleClickMemo</button>
      <button onClick={handleClick}>handleClick</button>
      <button onClick={handleClickNoRender}>handleClickNoRender</button>
      <br />
      <button onClick={() => setRender(!render)}>re-render</button>
    </div>
  );
}

export default function App() {
  return <MyComponent />;
}

ปุ่มแรกhandleClickMemoใช้ ฟังก์ชัน React.useCallbackเพื่อสร้างฟังก์ชันที่แคชโดย React วิธีนี้มีประโยชน์ในการหลีกเลี่ยงไม่ให้สร้างฟังก์ชันใหม่ทุกครั้งที่มีการอัปเดตคอมโพเนนต์ ฟังก์ชันสร้าง วัตถุ Proxy ใหม่ ตาม วัตถุ proxyDataอัปเดตคุณสมบัติ "ทดสอบ" ด้วยค่าใหม่ที่สร้างขึ้นแบบสุ่ม และตั้งค่าสถานะของproxyDataด้วยวัตถุที่สร้างขึ้นใหม่

const handleClickMemo = React.useCallback(() => {
    const updatedData = new Proxy(proxyData, {
      set(target, prop, value) {
        const success = Reflect.set(target, prop, value);
        if (success) {
          console.log(`Prop ${prop} modified with value ${value}`);
        }
        return success;
      },
    });
    updatedData.test = crypto.randomUUID();
    setProxyData(updatedData);
  }, []);

// without useCallback, do new proxy every time
  const handleClick = () => {
    const updatedData = new Proxy(proxyData, {
      set(target, prop, value) {
        const success = Reflect.set(target, prop, value);
        if (success) {
          console.warn(`Prop ${prop} modified with value ${value}`);
        }
        return success;
      },
    });
    updatedData.test = crypto.randomUUID();
    setProxyData(updatedData);
  };

// case where react doesn't render, but in console,
  // if it is a proxy the object is updated
  // BE CAREFUL when using proxies
  const handleClickNoRender = () => {
    proxyData.test = crypto.randomUUID();
    setProxyData(proxyData);
  };

โปรดทราบว่าการใช้Proxy อาจมีผลข้างเคียงและอาจทำให้เกิดปัญหาด้านประสิทธิภาพหากใช้ไม่ถูกต้อง นอกจากนี้ React อาจตรวจไม่พบสถานะการอัปเดตผ่าน วัตถุ Proxy ดังนั้นต้องใช้ความระมัดระวังเมื่อใช้ Proxies ภายในส่วนประกอบ React

ในลิงก์ นี้ คุณจะเห็นพฤติกรรมของแต่ละปุ่มในคอนโซล