پاسخگویی به رویدادها در React

mohsen1 ماه قبل4 هفته قبل
ارسال شده در
react/docs/v19

ری اکت به شما اجازه می‌دهد که توابع مدیریت رویداد (Event Handler) را به JSX خود اضافه کنید. مدیریت رویداد تابعی است که در پاسخ به تعاملاتی مانند کلیک، رفتن موس رو المان، و فوکوس بر روی ورودی‌های فرم، فعال می‌شوند.

افزودن مدیریت رویداد

برای افزودن یک مدیر رویداد، ابتدا باید یک تابع تعریف کنید و سپس آن را به عنوان ورودی به تگ JSX مورد نظر ارسال کنید. به عنوان مثال، در اینجا یک دکمه داریم که هنوز هیچ کاری انجام نمی‌دهد:

مشاهده کد زیر در CodeSandbox

      export default function Button() {
  return (
    <button>
      I don't do anything
    </button>
  );
}
    

با دنبال کردن سه مرحله زیر می توانید کد را طوری تغییر دهید که هنگام کلیک کاربر، پیامی را نمایش دهد:

  • تابعی به نام handleClick درون کامپوننت Button خود تعریف کنید.
  • منطق درون آن تابع را پیاده‌سازی کنید (از alert برای نمایش پیام استفاده کنید).
  • onClick={handleClick} را به JSX دکمه <button> اضافه کنید.

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function Button() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}
    

تابع handleClick را تعریف کردید و سپس آن را به عنوان یک ورودی به <button> ارسال کردید. handleClick یک مدیر رویداد است. توابع مدیر رویداد:

  • معمولاً درون کامپوننت‌های شما تعریف می‌شوند.
  • معمولا نام‌هایی دارند که با handle شروع می‌شوند و پس از آن نام رویداد قرار می‌گیرد.

به طور کلی، معمول است که نام تابع مدیریت رویداد را با handle بعلاوه نام رویداد نامگذاری کنید. شما در کدهای React معمولاً دستوراتی به صورت onClick={handleClick}، onMouseEnter={handleMouseEnter} و غیره را به وفور می‌بینید.

به طور جایگزین، می‌توانید یک مدیر رویداد را به صورت درون‌خطی نیز در JSX تعریف کنید:

      <button onClick={function handleClick() {
  alert('You clicked me!');
}}>
    

یا به طور مختصرتر، با استفاده از یک تابع پیکانی (Arrow):

      <button onClick={() => {
  alert('You clicked me!');
}}>
    

همه این سبک‌ها معادل هم هستند. مدیریت رویداد درون‌خطی برای توابع کوتاه مناسبتر است.

توابع ارسال شده بعنوان مدیریت رویداد باید بعنوان ورودی به تگ ارسال شوند، نه اینکه در زمان مقدار دهی به ویژگی فراخوانی شوند. به عنوان مثال:

ارسال یک تابع (صحیح)فراخوانی یک تابع (نادرست)
<button onClick={handleClick}><button onClick={handleClick()}>

در مثال اول، تابع handleClick به عنوان یک مدیر رویداد به onClick ارسال شده است. این دستور به React می‌گوید، زمانی که کاربر روی دکمه کلیک کرد، تابع شما را فراخوانی کند.

در مثال دوم، علامت () در انتهای دستور handleClick()، تابع را بلافاصله در زمان رندر اجرا می‌کند، بدون اینکه کلیکی صورت گرفته باشد. این به این دلیل است که جاوااسکریپت درون JSX مستقیماً اجرا می‌شود.

وقتی که شما کد را به صورت درون‌خطی می‌نویسید، همان مشکل به شکلی متفاوت بروز می‌کند:

ارسال یک تابع (صحیح)فراخوانی یک تابع (نادرست)
<button onClick={() => alert('...')}><button onClick={alert('...')}>

ارسال کد درون‌خطی به این صورت فعال نمی‌شود—این کد هر بار که کامپوننت رندر می‌شود، اجرا می‌شود:

      // پیام با هر بار رندر شدن دکمه به کاربر نمایش داده می شود
<button onClick={alert('You clicked me!')}>
    

اگر می‌خواهید مدیر رویداد خود را به صورت درون‌خطی تعریف کنید، آن را در یک تابع ناشناس به شکل زیر قرار دهید:

      <button onClick={() => alert('You clicked me!')}>
    

به جای این که کد درون تابع پیکانی را با هر رندر اجرا کنید، این روش تابعی برای فراخوانی در زمان کلیک کاربر ایجاد می‌کند.

در هر دو مورد، چیزی که ارسال می کنید یک تابع است:

  • <button onClick={handleClick}> تابع handleClick را ارسال می‌کند.
  • <button onClick={() => alert('...')}> تابع () => alert('...') را ارسال می‌کند.

بیشتر درباره توابع پیکانی بخوانید.

خواندن پروپ‌ها در مدیریت رویداد

بدلیل اینکه توابع مدیریت رویداد در داخل کامپوننت تعریف می‌شوند، به ورودی های کامپوننت دسترسی دارند. در اینجا دکمه ای را مشاهده می کنید که وقتی کلیک شود، یک هشدار با مقدار ورودی message به کاربر نمایش داده می شود:

مشاهده کد و نتیجه اجرای آن در CodeSandbox

      function AlertButton({ message, children }) {
  return (
    <button onClick={() => alert(message)}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <AlertButton message="Playing!">
        Play Movie
      </AlertButton>
      <AlertButton message="Uploading!">
        Upload Image
      </AlertButton>
    </div>
  );
}
    

این کار به دو دکمه اجازه می‌دهد که پیام‌های مختلفی را نمایش دهند. سعی کنید پیام‌های ارسال شده به آن‌ها را تغییر دهید.

ارسال مدیریت رویداد به عنوان پروپ

گاهی ممکن است بخواهید که کامپوننت والد، مدیر رویداد کامپوننت فرزند را مشخص کند. دکمه‌ها را در نظر بگیرید: بسته به اینکه شما از کامپوننت Button در کجا استفاده می‌کنید، ممکن است بخواهید تابع متفاوتی را اجرا کنید—شاید یکی فیلم را پخش کند و دیگری یک تصویر را بارگذاری کند.

برای این کار، یک ورودی بعنوان مدیر رویداد در کامپوننت فرزند به شکل زیر تعریف کنید تا والد بتواند تابع مدیر رویداد را برای فرزند ارسال کند:

مشاهده کد و نتیجه اجرای آن در CodeSandbox

      function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

function PlayButton({ movieName }) {
  function handlePlayClick() {
    alert(`Playing ${movieName}!`);
  }

  return (
    <Button onClick={handlePlayClick}>
      Play "{movieName}"
    </Button>
  );
}

function UploadButton() {
  return (
    <Button onClick={() => alert('Uploading!')}>
      Upload Image
    </Button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <PlayButton movieName="Kiki's Delivery Service" />
      <UploadButton />
    </div>
  );
}
    

در اینجا، کامپوننت Toolbar دکمه PlayButton و دکمه UploadButton را رندر می‌کند:

  • PlayButton تابع handlePlayClick را به عنوان پروپ onClick به Button درون خود ارسال می‌کند.
  • UploadButton تابع () => alert('Uploading!') را به عنوان پروپ onClick به Button درون خود ارسال می‌کند.

در نهایت، کامپوننت Button شما یک پروپ به نام onClick می‌پذیرد. این پروپ را مستقیماً به دکمه <button> داخلی مرورگر با onClick={onClick} ارسال می‌کند. این به React می‌گوید که تابع ارسال شده را در هنگام کلیک فراخوانی کند.

اگر شما از یک سیستم طراحی استفاده می‌کنید، معمول است که کامپوننت‌هایی مانند دکمه‌ها شامل استایل باشند اما رفتار را مشخص نکنند. در عوض، کامپوننت‌هایی مانند PlayButton و UploadButton مدیریت رویداد را به پایین منتقل می‌کنند.

نامگذاری پروپ‌های مدیر رویداد

کامپوننت‌های داخلی مانند <button> و <div> تنها از نام‌های رویداد مرورگر مانند onClick پشتیبانی می‌کنند. با این حال، هنگامی که شما کامپوننت‌های خود را می‌سازید، می‌توانید پروپ‌های مدیر رویداد خود را هر طور که می‌خواهید نامگذاری کنید.

به طور کلی، ورودی های مدیر رویداد باید با on شروع شوند و پس از آن یک حرف بزرگ قرار گیرد.

به عنوان مثال، پروپ onClick در کامپوننت Button می‌توانسته به نام onSmash نامگذاری شود:

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      function Button({ onSmash, children }) {
  return (
    <button onClick={onSmash}>
      {children}
    </button>
  );
}

export default function App() {
  return (
    <div>
      <Button onSmash={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onSmash={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}
    

در این مثال، <button onClick={onSmash}> نشان می‌دهد که دکمه مرورگر (<button> با حروف کوچک) هنوز به یک پروپ به نام onClick نیاز دارد، اما نام پروپی که کامپوننت سفارشی Button شما دریافت می‌کند، به خودتان بستگی دارد!

هنگامی که کامپوننت شما چندین رویداد منتشر می کند، می‌توانید ورودیهای مدیریت رویداد را برای هر کدام به طور خاص نامگذاری کنید. به عنوان مثال، کامپوننت Toolbar ورودی مدیریت رویداد onPlayMovie و onUploadImage را دریافت می‌کند:

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function App() {
  return (
    <Toolbar
      onPlayMovie={() => alert('Playing!')}
      onUploadImage={() => alert('Uploading!')}
    />
  );
}

function Toolbar({ onPlayMovie, onUploadImage }) {
  return (
    <div>
      <Button onClick={onPlayMovie}>
        Play Movie
      </Button>
      <Button onClick={onUploadImage}>
        Upload Image
      </Button>
    </div>
  );
}

function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}
    

به یاد داشته باشید که کامپوننت App نیازی ندارد که بداند که Toolbar با onPlayMovie یا onUploadImage چه کاری انجام می‌دهد. این جزئیات پیاده‌سازی Toolbar است. در اینجا، Toolbar آن‌ها را برای ویژگی onClick دکمه‌های خود تنظیم می‌کند، اما ممکن است بعداً آن‌ها را در زمان زدن کلیدهای صفحه کلید (میانبرها) فراخوانی کند. نامگذاری پروپ‌ها بر اساس تعاملات خاص برنامه مانند onPlayMovie به شما انعطاف‌پذیری بیشتری می‌دهد تا نحوه استفاده از آن‌ها را بعداً تغییر دهید.

مطمئن شوید که از تگ‌های HTML مناسب برای مدیریت رویداد خود استفاده کنید. به عنوان مثال، برای مدیریت کلیک‌ها، از <button onClick={handleClick}> به جای <div onClick={handleClick}> استفاده کنید. استفاده از المان <button> مرورگر امکاناتی مانند جابجایی با کیبورد را برای کاربر ممکن می‌کند. اگر شما از استایل پیش‌فرض دکمه مرورگر خوش‌تان نمی‌آید و می‌خواهید آن را شبیه‌تر به یک لینک یا یک عنصر UI دیگر کنید، می‌توانید با CSS انجام دهید. در مورد تگهای HTML بیشتر بدانید.

انتشار رویداد

تابع مدیریت رویداد همچنین می تواند رویدادها را از فرزندان خود، دریافت کنند. در این حالت به اصطلاح یک رویداد "حباب" می‌شود یا "انتشار" پیدا می‌کند: این رویداد از جایی که اتفاق افتاده شروع می‌شود و سپس در درخت DOM به سمت بالا می‌رود.

این <div> شامل دو دکمه است. هم <div> و هم دکمه ها دارای رویداد onClick خود هستند. به نظر شما کدام تابع مدیریت رویداد به هنگام کلیک بر روی دکمه فعال می‌شوند؟

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <button onClick={() => alert('Playing!')}>
        Play Movie
      </button>
      <button onClick={() => alert('Uploading!')}>
        Upload Image
      </button>
    </div>
  );
}
    

اگر بر روی هر یک از دکمه‌ها کلیک کنید، onClick آن دکمه اول اجرا خواهد شد و سپس onClick والد <div> اجرا می‌شود. بنابراین دو پیام ظاهر خواهند شد. اگر بر روی نوار ابزار کلیک کنید، تنها تابع onClick والد <div> اجرا می‌شود.

تمام رویدادها در React انتشار پیدا می‌کنند به جز onScroll، که تنها در تگ JSX که به آن اتصال داده شده کار می‌کند.

متوقف کردن انتشار

تابع مدیریت رویداد یک شی رویداد به عنوان آرگومان خود دریافت می‌کند. به طور معمول، این شی e نامیده می‌شود که به معنای "رویداد" است. شما می‌توانید از این شی برای خواندن اطلاعات رویداد استفاده کنید.

این شی همچنین به شما اجازه می‌دهد که انتشار را متوقف کنید. اگر می‌خواهید از رسیدن یک رویداد به کامپوننت‌های والدش جلوگیری کنید، باید e.stopPropagation() را مانند کامپوننت Button در کد زیر فراخوانی کنید:

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      function Button({ onClick, children }) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onClick();
    }}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <Button onClick={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onClick={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}
    

وقتی بر روی یک دکمه کلیک می‌کنید:

  • React تابع onClick ارسال شده به <button> را فراخوانی می‌کند.
  • آن تابع، که در Button تعریف شده، کارهای زیر را انجام می‌دهد:
    • e.stopPropagation() را فراخوانی می‌کند تا از حباب زدن رویداد به بالا جلوگیری کند.
    • تابع onClick را فراخوانی می‌کند، از کامپوننت Toolbar بعنوان ورودی ارسال شده است.
  • آن تابع، که در کامپوننت Toolbar تعریف شده، هشدار مخصوص دکمه را نمایش می‌دهد.
  • از آنجا که انتشار متوقف شده است، مدیر onClick والد <div> دیگر اجرا نمی‌شود.

نتیجه اجرای دستور e.stopPropagation()، این است که اکنون با کلیک بر روی دکمه‌ها تنها یک هشدار (از <button>) را نشان داده می شود و نه دو تا (از <button> و نوار ابزار والد <div>). کلیک بر روی دکمه با کلیک بر روی نوار ابزار اطراف برابر نیست، بنابراین متوقف کردن انتشار برای این کامپوننت منطقی است.

دریافت رویدادهای فاز Capture

در موارد نادر، شاید بخواهید تمام رویدادهای فرزندان را بگیرید، حتی اگر آنها انتشار را متوقف شده باشند. به عنوان مثال، شاید بخواهید هر کلیک را صرف‌نظر از منطق انتشار برای تجزیه و تحلیل ثبت کنید. برای این کار می توانید با افزودن Capture در انتهای نام رویداد به صورت زیر استفاده کنید:

      <div onClickCapture={() => { /* this runs first */ }}>
  <button onClick={e => e.stopPropagation()} />
  <button onClick={e => e.stopPropagation()} />
</div>
    

هر رویداد در سه فاز منتشر می‌شود:

  • در درخت دام از ریشه به سمت المان حرکت می کند و همه توابع onClickCapture ست شده را فراخوانی می‌کند.
  • مدیر onClick عنصر کلیک شده را اجرا می‌کند.
  • از المان هدف به سمت بالا حرکت می‌کند و همه توابع onClick ست شده را فراخوانی می‌کند.

رویدادهای فاز Capture برای کدهایی مانند روترها یا تجزیه و تحلیل مفیدند، اما کم پیش می آید که از آنها در کد برنامه استفاده کنید.

ارسال تابع مدیریت رویداد بعنوان جایگزینی برای انتشار

توجه کنید که چگونه تابع مدیر کلیک زیر، یک خط کد را اجرا می‌کند و سپس تابع onClick ارسال شده توسط والد را فراخوانی می‌کند:

      function Button({ onClick, children }) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onClick();
    }}>
      {children}
    </button>
  );
}
    

شما همچنین می‌توانید کدهای بیشتری به این تابع قبل از فراخوانی تابع رویداد پاس داده شده بوسیله onClick از والد را اجرا کنید. این الگو جایگزینی برای انتشار رویداد فراهم می‌کند. این به کامپوننت فرزند اجازه می‌دهد که رویداد را مدیریت کرده و در عین حال به کامپوننت والد امکان می‌دهد واکنشی اضافه بر فرزند انجام دهد. بر خلاف انتشار، این روش اتوماتیک نیست. اما مزیت این الگو این است که می‌توانید زنجیره‌ای از کد را که به عنوان نتیجه یک رویداد اجرا شده را به وضوح پیگیری کنید.

اگر کد شما وابسته انتشار است و پیگیری دنبل کردن اینکه کدام تابع مدیریت رویداد کجا و چرا اجرا می شوند، مشکل است، سعی کنید از این رویکرد به جای آن استفاده کنید.

جلوگیری از رفتار پیش‌فرض

برخی از رویدادها، رفتار پیش‌فرض مرورگر را به همراه دارند. به عنوان مثال، رویداد ارسال <form>، زمانی که دکمه‌ای در داخل آن کلیک می‌شود، به طور پیش‌فرض کل صفحه را بارگذاری می‌کند:

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function Signup() {
  return (
    <form onSubmit={() => alert('Submitting!')}>
      <input />
      <button>Send</button>
    </form>
  );
}
    

شما می‌توانید با فراخوانی e.preventDefault() بر روی شی رویداد، از این اتفاق جلوگیری کنید:

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function Signup() {
  return (
    <form onSubmit={e => {
      e.preventDefault();
      alert('Submitting!');
    }}>
      <input />
      <button>Send</button>
    </form>
  );
}
    

e.stopPropagation() و e.preventDefault() را با هم اشتباه نگیرید. هر دو مفید هستند، اما ارتباطی با هم ندارند:

  • e.stopPropagation() مدیریت رویداد متصل به تگ‌های والد را از اجرا شدن متوقف می‌کند.
  • e.preventDefault() از رفتار پیش‌فرض مرورگر جلوگیری می‌کند.

آیا مدیریت رویداد می‌توانند تاثیرات جانبی داشته باشند؟

قطعاً! مدیریت رویداد بهترین مکان برای تاثیرات جانبی هستند.

برخلاف توابع رندر، مدیریت رویداد نیازی به خالص بودن ندارند، بنابراین مکان خوبی برای تغییر مقادیر است—به عنوان مثال، تغییر مقدار ورودی در پاسخ به تایپ، یا تغییر یک لیست در پاسخ به فشار دکمه. با این حال، برای تغییر اطلاعات، ابتدا نیاز به روشی برای حفظ مقادیر دارید. در React، این کار با استفاده از وضعیت، حافظه یک کامپوننت انجام می‌شود. شما درباره این موضوع در مطالب بعدی خواهید آموخت.

جمع بندی

  • شما می‌توانید با ارسال یک تابع به عنوان پروپ به عنصری مانند <button> رویدادها را مدیریت کنید.
  • مدیریت رویداد باید ارسال شوند، نه فراخوانی! onClick={handleClick}، نه onClick={handleClick()}.
  • می‌توانید یک تابع مدیر رویداد را به صورت جداگانه یا درون‌خطی تعریف کنید.
  • توابع مدیریت رویداد در داخل یک کامپوننت تعریف می‌شوند و بنابراین می‌توانند به پروپ‌ها دسترسی داشته باشند.
  • می‌توانید یک مدیر رویداد را در والد تعریف کرده و به عنوان یک پروپ به فرزند ارسال کنید.
  • می‌توانید پروپ‌های مدیر رویداد خود را با نام‌های مخصوص برنامه تعریف کنید.
  • رویدادها به سمت بالا منتشر می‌شوند. کد e.stopPropagation() را فراخوانی کنید تا از این مسئله جلوگیری کنید.
  • رویدادها ممکن است رفتار پیش‌فرض مرورگر را بهمراه داشته باشند. e.preventDefault() را برای جلوگیری از آن فراخوانی کنید.
  • فراخوانی صریح ورودی تابع مدیریت رویداد در تابع مدیریت رویداد فرزند جایگزینی خوب برای انتشار رویداد است.

چالش ها

1. اصلاح یک مدیر رویداد

کلیک بر دکمه قرار است پس‌زمینه صفحه را بین سفید و سیاه تغییر دهد. با این حال، وقتی بر روی آن کلیک می‌کنید، هیچ اتفاقی نمی‌افتد. این مشکل را برطرف کنید. (نگران منطق داخل handleClick نباشید—آن قسمت به درستی عمل می کند.)

مشاهده کد اصلاح آن در CodeSandbox

2. متصل کردن رویدادها

کامپوننت ColorSwitch دکمه ای را رندر می‌کند که قرار است رنگ صفحه را تغییر دهد. آن را به پروپ مدیر رویداد onChangeColor که از والد دریافت می‌کند متصل کنید تا کلیک بر روی دکمه رنگ را تغییر دهد.

بعد از اینکه این کار را انجام دادید، توجه کنید که کلیک بر روی دکمه، شمارنده کلیک صفحه را نیز افزایش می‌دهد. در حالی که همکار شما که کامپوننت والد را نوشته است تأکید می‌کند که onChangeColor نبایدشمارنده را افزایش دهد. چه اتفاقی ممکن است افتاده باشد؟ آن را اصلاح کنید تا کلیک بر روی دکمه تنها رنگ را تغییر دهد و شمارشگر را افزایش ندهد. مشاهده کد اصلاح آن در CodeSandbox

راه حل چالش ها

چالش اول

مشکل این است که <button onClick={handleClick()}> تابع handleClick را در حین رندر به جای اینکه آن را ارسال کند، فراخوانی می‌کند. حذف () از انتهای نام تابع و قرار دادن <button onClick={handleClick}> مسئله را حل می‌کند: مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function LightSwitch() {
  function handleClick() {
    let bodyStyle = document.body.style;
    if (bodyStyle.backgroundColor === 'black') {
      bodyStyle.backgroundColor = 'white';
    } else {
      bodyStyle.backgroundColor = 'black';
    }
  }
  return (
    <button onClick={handleClick}>
      Toggle the lights
    </button>
  );
}
    

به طور جایگزین، می‌توانید فراخوانی را در یک تابع پیکانی قرار دهید، مانند <button onClick={() => handleClick()}>: مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function LightSwitch() {
  function handleClick() {
    let bodyStyle = document.body.style;
    if (bodyStyle.backgroundColor === 'black') {
      bodyStyle.backgroundColor = 'white';
    } else {
      bodyStyle.backgroundColor = 'black';
    }
  }
  return (
    <button onClick={() => handleClick()}>
      Toggle the lights
    </button>
  );
}
    

چالش دوم

اول، شما باید مدیر رویداد را مانند <button onClick={onChangeColor}> اضافه کنید. با این حال، این کار مشکلی برای افزایش شمارنده ایجاد می‌کند. اگر onChangeColor این کار را نمی‌کند، همانطور که همکار شما اصرار دارد، پس مشکل این است که این رویداد به سمت بالا منتشر می‌شود و برخی از توابع مدیرت رویداد در المان های بالاتر این کار را انجام می‌دهند. برای حل این مشکل، شما باید انتشار را متوقف کنید. اما فراموش نکنید که باید onChangeColor را فراخوانی کنید.

مشاهده کد و نتیجه اجرا آن در CodeSandbox

      export default function ColorSwitch({
  onChangeColor
}) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onChangeColor();
    }}>
      Change color
    </button>
  );
}
    
رای
0
ارسال نظر
مرتب سازی:
اولین نفری باشید که نظر می دهید!