From 27502be7b504e2b9564a80fae30964550e208927 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Tue, 2 May 2023 04:25:53 +0700 Subject: [PATCH 01/22] translate title for draft PR --- src/content/learn/separating-events-from-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index e932e8afd..4201494fd 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -1,5 +1,5 @@ --- -title: 'Separating Events from Effects' +title: 'Memisahkan Event dari Effect' --- From 1133e61eb088c8b9ce95621238c2cb9587ba1471 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 14:51:21 +0700 Subject: [PATCH 02/22] Fix title --- src/content/learn/separating-events-from-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 4201494fd..73885e92d 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -1,5 +1,5 @@ --- -title: 'Memisahkan Event dari Effect' +title: 'Membedakan Event dengan Effect' --- From 7f952e40681e7bc3e597fe7c89340584f34b26d4 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:07:49 +0700 Subject: [PATCH 03/22] translate intro and you will learn section --- src/content/learn/separating-events-from-effects.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 73885e92d..779b198f0 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -4,17 +4,17 @@ title: 'Membedakan Event dengan Effect' -Event handlers only re-run when you perform the same interaction again. Unlike event handlers, Effects re-synchronize if some value they read, like a prop or a state variable, is different from what it was during the last render. Sometimes, you also want a mix of both behaviors: an Effect that re-runs in response to some values but not others. This page will teach you how to do that. +Event handler hanya akan tereksekusi ketika kita melakukan interaksi yang berhubungan dengan event handler tersebut. Berbeda dengan event handler, Effect akan tereksekusi ulang jika nilai yang ada di _dependency array Effect_ berbeda/berubah dari nilai sebelumnya. Kadang kita juga ingin menggunakan memanfaatkan keduanya: Effect yang tereksekusi ketika beberapa nilai berubah, tetapi tidak pada yang lain. Halaman ini akan mengajari Anda cara melakukannya. -- How to choose between an event handler and an Effect -- Why Effects are reactive, and event handlers are not -- What to do when you want a part of your Effect's code to not be reactive -- What Effect Events are, and how to extract them from your Effects -- How to read the latest props and state from Effects using Effect Events +- Cara menentukan kapan menggunakan event handler atau Effect +- Mengapa Effect bersifat reaktif, dan event handler tidak +- Bagaimana cara kita membuat beberapa bagian dari kode Effect agar tidak reaktif +- Apa yang dimaksud Effect Events, dan bagaimana cara kita menggunakannya di Effect +- Cara membaca nilai props dan state dari Effects menggunakan Effect Events From 5234a1e1e3249427abb9e3aed429f8e70725f552 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:09:18 +0700 Subject: [PATCH 04/22] re-clarify intro --- src/content/learn/separating-events-from-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 779b198f0..83ae50a44 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -4,7 +4,7 @@ title: 'Membedakan Event dengan Effect' -Event handler hanya akan tereksekusi ketika kita melakukan interaksi yang berhubungan dengan event handler tersebut. Berbeda dengan event handler, Effect akan tereksekusi ulang jika nilai yang ada di _dependency array Effect_ berbeda/berubah dari nilai sebelumnya. Kadang kita juga ingin menggunakan memanfaatkan keduanya: Effect yang tereksekusi ketika beberapa nilai berubah, tetapi tidak pada yang lain. Halaman ini akan mengajari Anda cara melakukannya. +Event handler hanya akan tereksekusi ketika kita melakukan interaksi yang berhubungan dengan event handler tersebut. Berbeda dengan event handler, Effect akan tereksekusi ulang jika nilai yang ada di _dependency array Effect_ berbeda/berubah dari nilai sebelumnya. Kadang kita juga ingin memanfaatkan keduanya: Effect yang tereksekusi ketika beberapa nilai berubah, tetapi tidak pada yang lain. Halaman ini akan mengajari Anda cara melakukannya. From 18a4a26ebe64cb6012ba26eac06ed7cda0f2d336 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:24:32 +0700 Subject: [PATCH 05/22] translate how to choose between effect and event --- src/content/learn/separating-events-from-effects.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 83ae50a44..f5b1349a4 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -18,16 +18,15 @@ Event handler hanya akan tereksekusi ketika kita melakukan interaksi yang berhub -## Choosing between event handlers and Effects {/*choosing-between-event-handlers-and-effects*/} +## Cara menentukan kapan menggunakan event handler atau Effect {/*choosing-between-event-handlers-and-effects*/} -First, let's recap the difference between event handlers and Effects. +Mari kita mulai dengan merangkum perbedaan antara event handler dan Effect. -Imagine you're implementing a chat room component. Your requirements look like this: +Sekarang, bayangkan bahwa kita ingin menerapkan suatu komponen untuk ruang obrolan (_chatroom_). Persyaratan utamanya meliputi: -1. Your component should automatically connect to the selected chat room. -1. When you click the "Send" button, it should send a message to the chat. - -Let's say you've already implemented the code for them, but you're not sure where to put it. Should you use event handlers or Effects? Every time you need to answer this question, consider [*why* the code needs to run.](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events) +Komponen harus terhubung secara otomatis ke ruang obrolan yang sudah dipilih. +Ketika tombol 'Kirim' ditekan, kita harus dapat mengirimkan pesan ke dalam ruang obrolan. +Setelah kita mengimplementasikan kode untuk kebutuhan tersebut, mungkin akan timbul kebingungan dalam memilih tempat untuk meletakkannya. Apakah kita perlu menggunakan event handler atau malah menggunakan Effect? Setiap kali kita menghadapi pertanyaan seperti ini, penting untuk mempertimbangkan [*mengapa* kode tersebut perlu dijalankan](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events). ### Event handlers run in response to specific interactions {/*event-handlers-run-in-response-to-specific-interactions*/} From a3dbb24776d8cf51bb115786b00d72b7dbe21a84 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:26:19 +0700 Subject: [PATCH 06/22] fix formatting previous commit --- src/content/learn/separating-events-from-effects.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index f5b1349a4..1ec43ea8d 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -24,8 +24,9 @@ Mari kita mulai dengan merangkum perbedaan antara event handler dan Effect. Sekarang, bayangkan bahwa kita ingin menerapkan suatu komponen untuk ruang obrolan (_chatroom_). Persyaratan utamanya meliputi: -Komponen harus terhubung secara otomatis ke ruang obrolan yang sudah dipilih. -Ketika tombol 'Kirim' ditekan, kita harus dapat mengirimkan pesan ke dalam ruang obrolan. +1. Komponen harus terhubung secara otomatis ke ruang obrolan yang sudah dipilih. +1. Ketika tombol 'Kirim' ditekan, kita harus dapat mengirimkan pesan ke dalam ruang obrolan. + Setelah kita mengimplementasikan kode untuk kebutuhan tersebut, mungkin akan timbul kebingungan dalam memilih tempat untuk meletakkannya. Apakah kita perlu menggunakan event handler atau malah menggunakan Effect? Setiap kali kita menghadapi pertanyaan seperti ini, penting untuk mempertimbangkan [*mengapa* kode tersebut perlu dijalankan](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events). ### Event handlers run in response to specific interactions {/*event-handlers-run-in-response-to-specific-interactions*/} From 4a16aab683d18d830c3614b360b93b0f4bed18f0 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:32:20 +0700 Subject: [PATCH 07/22] translate next section --- src/content/learn/separating-events-from-effects.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 1ec43ea8d..0976025b5 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -29,9 +29,9 @@ Sekarang, bayangkan bahwa kita ingin menerapkan suatu komponen untuk ruang obrol Setelah kita mengimplementasikan kode untuk kebutuhan tersebut, mungkin akan timbul kebingungan dalam memilih tempat untuk meletakkannya. Apakah kita perlu menggunakan event handler atau malah menggunakan Effect? Setiap kali kita menghadapi pertanyaan seperti ini, penting untuk mempertimbangkan [*mengapa* kode tersebut perlu dijalankan](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events). -### Event handlers run in response to specific interactions {/*event-handlers-run-in-response-to-specific-interactions*/} +### Event handler tereksekusi karena interaksi tertentu {/*event-handlers-run-in-response-to-specific-interactions*/} -From the user's perspective, sending a message should happen *because* the particular "Send" button was clicked. The user will get rather upset if you send their message at any other time or for any other reason. This is why sending a message should be an event handler. Event handlers let you handle specific interactions: +Dari sudut pandang pengguna, pengiriman pesan harus terjadi karena tombol "Kirim" tertentu diklik. Pengguna akan agak kesal jika kita mengirim pesan mereka di waktu lain atau karena alasan lain. Inilah sebabnya mengapa mengirim pesan harus menjadi event handler. Event handler memungkinkan Anda menangani interaksi tertentu: ```js {4-6} function ChatRoom({ roomId }) { @@ -50,7 +50,7 @@ function ChatRoom({ roomId }) { } ``` -With an event handler, you can be sure that `sendMessage(message)` will *only* run if the user presses the button. +Dengan event handler, kita bisa yakin bahwa `sendMessage(message)` *hanya* akan tereksekusi jika pengguna menekan tombol. ### Effects run whenever synchronization is needed {/*effects-run-whenever-synchronization-is-needed*/} From d84a139c88e563686a8d10187802c1d5d9271de2 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 15:43:42 +0700 Subject: [PATCH 08/22] reclarify intro --- src/content/learn/separating-events-from-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 0976025b5..5316fe36c 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -4,7 +4,7 @@ title: 'Membedakan Event dengan Effect' -Event handler hanya akan tereksekusi ketika kita melakukan interaksi yang berhubungan dengan event handler tersebut. Berbeda dengan event handler, Effect akan tereksekusi ulang jika nilai yang ada di _dependency array Effect_ berbeda/berubah dari nilai sebelumnya. Kadang kita juga ingin memanfaatkan keduanya: Effect yang tereksekusi ketika beberapa nilai berubah, tetapi tidak pada yang lain. Halaman ini akan mengajari Anda cara melakukannya. +Event handler hanya akan tereksekusi ketika kita melakukan interaksi tertentu. Berbeda dengan event handler, Effect akan tereksekusi ulang jika nilai yang ada di _dependency array Effect_ berbeda/berubah dari nilai sebelumnya. Kadang kita juga ingin memanfaatkan keduanya: Effect yang tereksekusi ketika beberapa nilai berubah, tetapi tidak pada yang lain. Halaman ini akan mengajari Anda cara melakukannya. From ce6b4aae46fd17fd88c0dc219b81ad68226f2101 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 16:09:09 +0700 Subject: [PATCH 09/22] translate next section --- .../learn/separating-events-from-effects.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 5316fe36c..c3e0d8433 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -44,7 +44,7 @@ function ChatRoom({ roomId }) { return ( <> setMessage(e.target.value)} /> - ; + ; ); } @@ -52,11 +52,11 @@ function ChatRoom({ roomId }) { Dengan event handler, kita bisa yakin bahwa `sendMessage(message)` *hanya* akan tereksekusi jika pengguna menekan tombol. -### Effects run whenever synchronization is needed {/*effects-run-whenever-synchronization-is-needed*/} +### Effect tereksekusi ketika sinkronisasi diperlukan {/*effects-run-whenever-synchronization-is-needed*/} -Recall that you also need to keep the component connected to the chat room. Where does that code go? +Jangan lupa bahwa kita juga harus menjaga agar komponen kita tetap terhubung dengan ruang obrolan. Kita perlu memikirkan ke mana kode tersebut seharusnya ditempatkan. -The *reason* to run this code is not some particular interaction. It doesn't matter why or how the user navigated to the chat room screen. Now that they're looking at it and could interact with it, the component needs to stay connected to the selected chat server. Even if the chat room component was the initial screen of your app, and the user has not performed any interactions at all, you would *still* need to connect. This is why it's an Effect: +Kita harus menjalankan kode tersebut untuk memastikan komponen ini tetap terhubung ke server obrolan yang dipilih, *bukan* karena interaksi tertentu. Tidak peduli bagaimana atau mengapa pengguna berpindah ke layar ruang obrolan, yang penting adalah sekarang mereka melihatnya dan dapat berinteraksi dengannya. Oleh karena itu, kita perlu memastikan komponen kita tetap terhubung ke server obrolan yang dipilih, bahkan jika pengguna tidak berinteraksi dengan aplikasi kita sama sekali. Inilah sebab mengapa kita perlu menggunakan Effect untuk memastikan hal tersebut terjadi: ```js {3-9} function ChatRoom({ roomId }) { @@ -72,7 +72,7 @@ function ChatRoom({ roomId }) { } ``` -With this code, you can be sure that there is always an active connection to the currently selected chat server, *regardless* of the specific interactions performed by the user. Whether the user has only opened your app, selected a different room, or navigated to another screen and back, your Effect ensures that the component will *remain synchronized* with the currently selected room, and will [re-connect whenever it's necessary.](/learn/lifecycle-of-reactive-effects#why-synchronization-may-need-to-happen-more-than-once) +Dengan kode ini, kita dapat memastikan adanya koneksi aktif ke server obrolan yang dipilih saat ini, *tanpa* perlu bergantung pada interaksi pengguna. Tidak peduli apakah pengguna hanya membuka aplikasi kita, memilih ruangan yang berbeda, atau menavigasi ke layar lain kemudian kembali, Effect dapat memberikan jaminan bahwa komponen akan *tetap disinkronisasi* dengan ruangan obrolan yang dipilih saat ini. Sehingga, komponen akan selalu terhubung ke server obrolan yang dipilih saat ini dan akan [tersambung kembali setiap kali diperlukan.](/learn/lifecycle-of-reactive-effects#why-synchronization-may-need-to-happen-more-than-once) @@ -97,9 +97,9 @@ function ChatRoom({ roomId }) { return ( <> -

Welcome to the {roomId} room!

+

Selamat datang di room {roomId}!

setMessage(e.target.value)} /> - + ); } @@ -110,18 +110,18 @@ export default function App() { return ( <> {show &&
} {show && } @@ -132,17 +132,17 @@ export default function App() { ```js chat.js export function sendMessage(message) { - console.log('🔵 You sent: ' + message); + console.log('🔵 Anda mengirim: ' + message); } export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Implementasi yang sesungguhnya akan terhubung ke server. return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Menghubungkan ke room "' + roomId + '" pada url ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Room "' + roomId + '" terputus pada url ' + serverUrl); } }; } From 6e161e48d356b3a85b6de20f9955ee4b0dc356ad Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Thu, 4 May 2023 16:32:11 +0700 Subject: [PATCH 10/22] translate next section --- .../learn/separating-events-from-effects.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index c3e0d8433..a10d02c6f 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -154,13 +154,13 @@ input, select { margin-right: 20px; }
-## Reactive values and reactive logic {/*reactive-values-and-reactive-logic*/} +## Nilai reaktif dan logika reaktif {/*reactive-values-and-reactive-logic*/} -Intuitively, you could say that event handlers are always triggered "manually", for example by clicking a button. Effects, on the other hand, are "automatic": they run and re-run as often as it's needed to stay synchronized. +Secara intuitif, kita bisa mengatakan bahwa event handler selalu dipicu "secara manual", misalnya dengan mengklik sebuah tombol. Sementara itu, Effects berjalan "secara otomatis". Mereka berjalan dan berjalan kembali sesering yang diperlukan untuk memastikan sinkronisasi tetap terjaga. -There is a more precise way to think about this. +Namun, ada cara yang lebih tepat untuk memikirkan perbedaan antara keduanya. -Props, state, and variables declared inside your component's body are called reactive values. In this example, `serverUrl` is not a reactive value, but `roomId` and `message` are. They participate in the rendering data flow: +Props, status, dan variabel yang dideklarasikan di dalam tubuh komponen disebut nilai reaktif. Dalam contoh ini, `serverUrl` bukan merupakan nilai reaktif, melainkan `roomId` dan `message`. Keduanya berpartisipasi dalam aliran data rendering, sehingga harus diatur sebagai nilai reaktif agar sinkronisasi dapat terjaga: ```js [[2, 3, "roomId"], [2, 4, "message"]] const serverUrl = 'https://localhost:1234'; @@ -172,12 +172,12 @@ function ChatRoom({ roomId }) { } ``` -Reactive values like these can change due to a re-render. For example, the user may edit the `message` or choose a different `roomId` in a dropdown. Event handlers and Effects respond to changes differently: +Nilai reaktif seperti ini dapat berubah karena rendering ulang suatu komponen. Misalnya, pengguna dapat melakukan beberapa tindakan, seperti mengedit `message` atau memilih `roomId` yang berbeda di menu drop-down. Event handler dan Effect merespon perubahan tersebut dengan cara yang berbeda: -- **Logic inside event handlers is *not reactive.*** It will not run again unless the user performs the same interaction (e.g. a click) again. Event handlers can read reactive values without "reacting" to their changes. -- **Logic inside Effects is *reactive.*** If your Effect reads a reactive value, [you have to specify it as a dependency.](/learn/lifecycle-of-reactive-effects#effects-react-to-reactive-values) Then, if a re-render causes that value to change, React will re-run your Effect's logic with the new value. +- **Logika di dalam event handler bersifat *non-reaktif.*** Ketika sebuah event handler dijalankan (mengikuti tindakan pengguna seperti klik), mereka membaca nilai reaktif tanpa bereaksi terhadap perubahannya. Artinya, jika Anda ingin event handler membaca suatu nilai reaktif, mereka tidak akan merespon ketika nilainya berubah kecuali tindakan pengguna yang sama kembali dijalankan. +- **Logika di dalam Effect bersifat *reaktif.*** Jika Anda menggunakan Effects untuk membaca nilai reaktif, Anda harus [mendeklarasikannya sebagai salah satu dependensi Effect tersebut.](/learn/lifecycle-of-reactive-effects#effects-react-to-reactive-values) Kemudian jika render ulang menyebabkan nilai tersebut berubah, React akan menjalankan kembali logika Effect Anda dengan nilai yang baru, sehingga memastikan sinkronisasi data terjaga. -Let's revisit the previous example to illustrate this difference. +Mari kita lihat kembali contoh sebelumnya untuk mengilustrasikan perbedaan ini. ### Logic inside event handlers is not reactive {/*logic-inside-event-handlers-is-not-reactive*/} From d1c83aad3e902471c1b37a3c859b3754b6ae89ce Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Fri, 5 May 2023 09:56:09 +0700 Subject: [PATCH 11/22] translate next section --- .../learn/separating-events-from-effects.md | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index a10d02c6f..61145cfbc 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -160,7 +160,7 @@ Secara intuitif, kita bisa mengatakan bahwa event handler selalu dipicu "secara Namun, ada cara yang lebih tepat untuk memikirkan perbedaan antara keduanya. -Props, status, dan variabel yang dideklarasikan di dalam tubuh komponen disebut nilai reaktif. Dalam contoh ini, `serverUrl` bukan merupakan nilai reaktif, melainkan `roomId` dan `message`. Keduanya berpartisipasi dalam aliran data rendering, sehingga harus diatur sebagai nilai reaktif agar sinkronisasi dapat terjaga: +Props, status, dan variabel yang dideklarasikan di dalam komponen disebut nilai reaktif. Dalam contoh ini, `serverUrl` bukan merupakan nilai reaktif, melainkan `roomId` dan `message`. Keduanya berpartisipasi dalam aliran data rendering, sehingga harus diatur sebagai nilai reaktif agar sinkronisasi dapat terjaga: ```js [[2, 3, "roomId"], [2, 4, "message"]] const serverUrl = 'https://localhost:1234'; @@ -179,9 +179,9 @@ Nilai reaktif seperti ini dapat berubah karena rendering ulang suatu komponen. M Mari kita lihat kembali contoh sebelumnya untuk mengilustrasikan perbedaan ini. -### Logic inside event handlers is not reactive {/*logic-inside-event-handlers-is-not-reactive*/} +### Kode di dalam event handler bersifat tidak reaktif {/*logic-inside-event-handlers-is-not-reactive*/} -Take a look at this line of code. Should this logic be reactive or not? +Mari kita lihat baris kode ini. Apakah kode ini seharusnya merupakan nilai reaktif atau tidak? ```js [[2, 2, "message"]] // ... @@ -189,7 +189,7 @@ Take a look at this line of code. Should this logic be reactive or not? // ... ``` -From the user's perspective, **a change to the `message` does _not_ mean that they want to send a message.** It only means that the user is typing. In other words, the logic that sends a message should not be reactive. It should not run again only because the reactive value has changed. That's why it belongs in the event handler: +Dari sudut pandang pengguna, **perubahan dalam nilai `message` _tidak_ selalu berarti mereka hendak mengirim pesan**. Hal ini mungkin hanya berarti bahwa pengguna sedang mengetik. Oleh karena itu, logika pengiriman pesan tidak seharusnya diatur sebagai nilai reaktif, agar tidak dipicu secara otomatis setiap kali nilai message berubah. Sebaliknya, logika ini sebaiknya diimplementasikan pada event handler: ```js {2} function handleSendClick() { @@ -197,11 +197,11 @@ From the user's perspective, **a change to the `message` does _not_ mean that th } ``` -Event handlers aren't reactive, so `sendMessage(message)` will only run when the user clicks the Send button. +Event handler bersifat tidak reaktif, jadi `sendMessage(message)` hanya akan tereksekusi saat pengguna mengklik tombol Kirim. -### Logic inside Effects is reactive {/*logic-inside-effects-is-reactive*/} +### Kode didalam Effect bersifat reaktif {/*logic-inside-effects-is-reactive*/} -Now let's return to these lines: +Sekarang mari kita kembali ke baris ini: ```js [[2, 2, "roomId"]] // ... @@ -210,7 +210,7 @@ Now let's return to these lines: // ... ``` -From the user's perspective, **a change to the `roomId` *does* mean that they want to connect to a different room.** In other words, the logic for connecting to the room should be reactive. You *want* these lines of code to "keep up" with the reactive value, and to run again if that value is different. That's why it belongs in an Effect: +Dari sudut pandang pengguna, **perubahan pada `roomId` _berarti_ mereka ingin terhubung ke ruangan yang berbeda**. Dengan kata lain, logika untuk menghubungkan ke _chatroom_ harus reaktif. Kita _ingin_ baris kode ini "mengikuti" nilai reaktif, dan berjalan lagi jika nilai tersebut berubah. Itu sebabnya kita implementasikan sebagai Effect: ```js {2-3} useEffect(() => { @@ -222,43 +222,43 @@ From the user's perspective, **a change to the `roomId` *does* mean that they wa }, [roomId]); ``` -Effects are reactive, so `createConnection(serverUrl, roomId)` and `connection.connect()` will run for every distinct value of `roomId`. Your Effect keeps the chat connection synchronized to the currently selected room. +Effect bersifat reaktif, jadi `createConnection(serverUrl, roomId)` dan `connection.connect()` akan terksekusi setiap kali nilai `roomId` berubah. Effect ini membantu kita menjaga koneksi tetap tersinkronasi sesuai _chatroom_ yang dipilih saat ini. -## Extracting non-reactive logic out of Effects {/*extracting-non-reactive-logic-out-of-effects*/} +## Mengekstrak logika non-reaktif dari Effect {/*extracting-non-reactive-logic-out-of-effects*/} -Things get more tricky when you want to mix reactive logic with non-reactive logic. +Semuanya menjadi lebih kompleks ketika kita ingin menggabungkan logika reaktif dengan logika non-reaktif. -For example, imagine that you want to show a notification when the user connects to the chat. You read the current theme (dark or light) from the props so that you can show the notification in the correct color: +Misalnya, pertimbangkan skenario di mana kita ingin menampilkan notifikasi saat pengguna terhubung ke obrolan. Serta kita juga ingin membaca nilai tema saat ini (terang atau gelap) dari props, sehingga notifikasi yang ditampilkan akan memiliki warna yang tepat sesuai dengan tema yang digunakan: ```js {1,4-6} function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); connection.connect(); // ... ```` -However, `theme` is a reactive value (it can change as a result of re-rendering), and [every reactive value read by an Effect must be declared as its dependency.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) Now you have to specify `theme` as a dependency of your Effect: +Namun, `theme` adalah nilai reaktif (dapat berubah sebagai hasil dari re-render), dan [setiap nilai reaktif yang dibaca oleh Effect harus dideklarasikan sebagai dependensi Effect tersebut.](/learn/lifecycle-of-reactive-effects#react-verifies-that-you-specified-every-reactive-value-as-a-dependency) Sekarang kita harus menentukan `theme` sebagai dependensi Effect: ```js {5,11} function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); connection.connect(); return () => { connection.disconnect() }; - }, [roomId, theme]); // ✅ All dependencies declared + }, [roomId, theme]); // ✅ Semua dependensi telah didelarasikan // ... ```` -Play with this example and see if you can spot the problem with this user experience: +Cobalah contoh di bawah ini dan cari tahu apakah kamu bisa menemukan masalah pada program berikut: @@ -290,13 +290,13 @@ function ChatRoom({ roomId, theme }) { useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); connection.connect(); return () => connection.disconnect(); }, [roomId, theme]); - return

Welcome to the {roomId} room!

+ return

Selamat datang di room {roomId}!

} export default function App() { @@ -305,14 +305,14 @@ export default function App() { return ( <>
-When the `roomId` changes, the chat re-connects as you would expect. But since `theme` is also a dependency, the chat *also* re-connects every time you switch between the dark and the light theme. That's not great! +Ketika `roomId` berubah, chat terhubung kembali seperti yang diharapkan. Tetapi karena `theme` juga termasuk dependensi Effect, chat *juga* terhubung kembali setiap kita beralih antara tema gelap dan terang. Itu tidak bagus! -In other words, you *don't* want this line to be reactive, even though it is inside an Effect (which is reactive): +Dengan kata lain, kita *tidak* ingin baris ini menjadi reaktif, meskipun berada di dalam Effect (yang reaktif): ```js // ... @@ -396,52 +396,52 @@ In other words, you *don't* want this line to be reactive, even though it is ins // ... ``` -You need a way to separate this non-reactive logic from the reactive Effect around it. +Kita memerlukan cara untuk memisahkan logika non-reaktif ini dari Effect reaktif di sekitarnya. -### Declaring an Effect Event {/*declaring-an-effect-event*/} +### Mendeklarasikan Effect Event {/*declaring-an-effect-event*/} -This section describes an **experimental API that has not yet been released** in a stable version of React. +Bagian ini menjelaskan **API eksperimental yang belum dirilis** dalam versi React yang stabil. -Use a special Hook called [`useEffectEvent`](/reference/react/experimental_useEffectEvent) to extract this non-reactive logic out of your Effect: +Gunakan Hook khusus [`useEffectEvent`](/reference/react/experimental_useEffectEvent) untuk mengekstrak logika non-reaktif ini dari Effect: ```js {1,4-6} import { useEffect, useEffectEvent } from 'react'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); // ... ```` -Here, `onConnected` is called an *Effect Event.* It's a part of your Effect logic, but it behaves a lot more like an event handler. The logic inside it is not reactive, and it always "sees" the latest values of your props and state. +Disini, `onConnected` disebut dengan *Effect Event.* Meskipun merupakan bagian dari logika Effect, namun mempunyai sifat seperti event handler. Logika di dalamnya tidak reaktif, dan selalu memperhatikan nilai terbaru dari props dan state. -Now you can call the `onConnected` Effect Event from inside your Effect: +Sekarang Anda dapat memanggil Effect Event `onConnected` dari dalam Effect: ```js {2-4,9,13} function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.on('connected', () => { - onConnected(); + onConnected(); }); connection.connect(); return () => connection.disconnect(); - }, [roomId]); // ✅ All dependencies declared + }, [roomId]); // ✅ Semua dependensi dideklarasikan, karena theme tidak lagi merupakan dependensi Effect, maka tidak akan tereksekusi ulang jika nilai theme berubah. // ... ``` -This solves the problem. Note that you had to *remove* `onConnected` from the list of your Effect's dependencies. **Effect Events are not reactive and must be omitted from dependencies.** +Masalah terpecahkan. Perhatikan bahwa Anda harus *menghapus* `onConnected` dari daftar dependensi Effect. **Effect Event tidak reaktif dan harus dihilangkan dari dependensi.** -Verify that the new behavior works as you would expect: +Pastikan bahwa program baru berfungsi seperti yang kita harapkan: @@ -472,7 +472,7 @@ const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { - showNotification('Connected!', theme); + showNotification('Terhubung!', theme); }); useEffect(() => { @@ -484,7 +484,7 @@ function ChatRoom({ roomId, theme }) { return () => connection.disconnect(); }, [roomId]); - return

Welcome to the {roomId} room!

+ return

Selamat datang di room {roomId}!

} export default function App() { @@ -493,14 +493,14 @@ export default function App() { return ( <>
-You can think of Effect Events as being very similar to event handlers. The main difference is that event handlers run in response to a user interactions, whereas Effect Events are triggered by you from Effects. Effect Events let you "break the chain" between the reactivity of Effects and code that should not be reactive. +Anda dapat menganggap Effect Event sangat mirip dengan event handler. Perbedaan utamanya adalah event handler dijalankan sebagai respons terhadap interaksi pengguna, sedangkan Effect Event dipicu oleh Anda dari Effect. Effect Event memungkinkan kita "memutus rantai" antara reaktivitas Effect dan kode yang seharusnya tidak reaktif. ### Reading latest props and state with Effect Events {/*reading-latest-props-and-state-with-effect-events*/} From 2c3046a6fb885992323c0c0fe7079f39c1e61b21 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Fri, 5 May 2023 12:32:25 +0700 Subject: [PATCH 12/22] translate next section --- .../learn/separating-events-from-effects.md | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 61145cfbc..d4cc69171 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -576,17 +576,17 @@ label { display: block; margin-top: 10px; } Anda dapat menganggap Effect Event sangat mirip dengan event handler. Perbedaan utamanya adalah event handler dijalankan sebagai respons terhadap interaksi pengguna, sedangkan Effect Event dipicu oleh Anda dari Effect. Effect Event memungkinkan kita "memutus rantai" antara reaktivitas Effect dan kode yang seharusnya tidak reaktif. -### Reading latest props and state with Effect Events {/*reading-latest-props-and-state-with-effect-events*/} +### Membaca props dan state terbaru dengan Effect Event {/*reading-latest-props-and-state-with-effect-events*/} -This section describes an **experimental API that has not yet been released** in a stable version of React. +Bagian ini menjelaskan **API eksperimental yang belum dirilis** dalam versi React yang stabil. -Effect Events let you fix many patterns where you might be tempted to suppress the dependency linter. +Effect Event memungkinkan kita memperbaiki banyak pola di mana kamu mungkin tergoda untuk _supress_ warning dari _dependency linter_. -For example, say you have an Effect to log the page visits: +Misalnya, kita memiliki Effect untuk mencatat _log_ kunjungan halaman: ```js function Page() { @@ -597,7 +597,7 @@ function Page() { } ``` -Later, you add multiple routes to your site. Now your `Page` component receives a `url` prop with the current path. You want to pass the `url` as a part of your `logVisit` call, but the dependency linter complains: +Kemudian, kita menambahkan beberapa rute ke situs tersebut. Sekarang komponen `Page` kita menerima prop `url` dengan _path_ saat ini. Kita ingin pass `url` ke parameter function `logVisit`, tetapi _dependency linter_ pasti akan mengeluarkan warning: ```js {1,3} function Page({ url }) { @@ -608,18 +608,18 @@ function Page({ url }) { } ``` -Think about what you want the code to do. You *want* to log a separate visit for different URLs since each URL represents a different page. In other words, this `logVisit` call *should* be reactive with respect to the `url`. This is why, in this case, it makes sense to follow the dependency linter, and add `url` as a dependency: +Sekarang mari pikirkan apa tujuan awal dari kode ini. Kita *ingin* mencatat setiap kunjungan terpisah untuk tiap URL karena setiap URL merepresentasikan halaman yang berbeda. Artinya, pemanggilan `logVisit` ini seharusnya _berperilaku reaktif_ terhadap `url`. Oleh karena itu, dalam kasus ini, akan lebih baik jika kita mengikuti _dependency linter_ dan menambahkan `url` sebagai salah satu dependensi Effect. ```js {4} function Page({ url }) { useEffect(() => { logVisit(url); - }, [url]); // ✅ All dependencies declared + }, [url]); // ✅ Semua dependensi telah dideklarasikan // ... } ``` -Now let's say you want to include the number of items in the shopping cart together with every page visit: +Sekarang katakanlah kita ingin memasukkan jumlah barang di keranjang belanja bersama dengan setiap kunjungan halaman: ```js {2-3,6} function Page({ url }) { @@ -633,9 +633,9 @@ function Page({ url }) { } ``` -You used `numberOfItems` inside the Effect, so the linter asks you to add it as a dependency. However, you *don't* want the `logVisit` call to be reactive with respect to `numberOfItems`. If the user puts something into the shopping cart, and the `numberOfItems` changes, this *does not mean* that the user visited the page again. In other words, *visiting the page* is, in some sense, an "event". It happens at a precise moment in time. +Kamu menggunakan `numberOfItems` di dalam Effect, sehingga linter meminta agar kamu menambahkannya sebagai salah satu dependensi. Namun, sebenarnya kamu *tidak ingin* memanggil `logVisit` secara reaktif terhadap `numberOfItems`. Jika pengguna menambahkan barang ke dalam keranjang belanja dan `numberOfItems` berubah, ini tidak berarti bahwa pengguna telah mengunjungi kembali halaman tersebut. Dalam artian lain, melakukan *kunjungan ke halaman* adalah suatu "peristiwa (_event_)" yang terjadi pada saat tertentu. -Split the code in two parts: +Sebaiknya, pisahkan kode tersebut menjadi dua bagian: ```js {5-7,10} function Page({ url }) { @@ -648,20 +648,20 @@ function Page({ url }) { useEffect(() => { onVisit(url); - }, [url]); // ✅ All dependencies declared + }, [url]); // ✅ Semua dependensi telah dideklarasikan // ... } ``` -Here, `onVisit` is an Effect Event. The code inside it isn't reactive. This is why you can use `numberOfItems` (or any other reactive value!) without worrying that it will cause the surrounding code to re-execute on changes. +Di sini, `onVisit` adalah suatu Effect Event. Kode di dalamnya tidak bersifat reaktif. Oleh karena itu, kta dapat menggunakan `numberOfItems` (atau reactive value lain!) tanpa khawatir mengakibatkan kode di sekitarnya dijalankan ulang saat terjadi perubahan. -On the other hand, the Effect itself remains reactive. Code inside the Effect uses the `url` prop, so the Effect will re-run after every re-render with a different `url`. This, in turn, will call the `onVisit` Effect Event. +Namun di sisi lain, Effect itu sendiri tetap bersifat reaktif. Kode di dalam Effect menggunakan prop `url`, sehingga Effect tersebut akan dijalankan ulang setelah setiap render dengan `url` yang berbeda. Hal ini pada akhirnya akan memanggil Effect Event `onVisit`. -As a result, you will call `logVisit` for every change to the `url`, and always read the latest `numberOfItems`. However, if `numberOfItems` changes on its own, this will not cause any of the code to re-run. +Akibatnya, `logVisit` akan terpanggil untuk setiap perubahan pada `url`, dan selalu membaca `numberOfItems` yang terbaru. Namun jika hanya nilai `numberOfItems` yang berubah, hal ini tidak akan menyebabkan kode berjalan ulang. -You might be wondering if you could call `onVisit()` with no arguments, and read the `url` inside it: +Mungkin kamu bertanya-tanya apakah bisa memanggil `onVisit()` tanpa argumen, dan membaca nilai `url` di dalamnya: ```js {2,6} const onVisit = useEffectEvent(() => { @@ -673,7 +673,7 @@ You might be wondering if you could call `onVisit()` with no arguments, and read }, [url]); ``` -This would work, but it's better to pass this `url` to the Effect Event explicitly. **By passing `url` as an argument to your Effect Event, you are saying that visiting a page with a different `url` constitutes a separate "event" from the user's perspective.** The `visitedUrl` is a *part* of the "event" that happened: +Cara tersebut memang bisa dilakukan, tetapi sebaiknya kita memasukkan nilai `url` secara eksplisit ke dalam Effect Event. **Dengan memasukkan `url` sebagai argumen ke dalam Effect Event, kita menyatakan bahwa kunjungan halaman dengan `url` yang berbeda merupakan sebuah "_event_" yang terpisah bagi pengguna.** Artinya, `visitedUrl` merupakan *bagian* dari "_event_" tersebut. ```js {1-2,6} const onVisit = useEffectEvent(visitedUrl => { @@ -685,9 +685,9 @@ This would work, but it's better to pass this `url` to the Effect Event explicit }, [url]); ``` -Since your Effect Event explicitly "asks" for the `visitedUrl`, now you can't accidentally remove `url` from the Effect's dependencies. If you remove the `url` dependency (causing distinct page visits to be counted as one), the linter will warn you about it. You want `onVisit` to be reactive with regards to the `url`, so instead of reading the `url` inside (where it wouldn't be reactive), you pass it *from* your Effect. +Karena Effect Event kita secara eksplisit "meminta" nilai `visitedUrl`, maka sekarang kita tidak dapat secara tidak sengaja menghapus `url` dari dependensi Effect tersebut. Jika kamu menghapus `url` dari dependensi (dan menyebabkan penghitungan kunjungan halaman yang berbeda terhitung sebagai satu), maka linter akan memberikan peringatan. Kamu ingin `onVisit` berperilaku reaktif terhadap `url`, sehingga daripada membaca nilai `url` dari dalam (yang tidak bersifat reaktif), kamu _pass_ nilai url *dari* dalam Effect. -This becomes especially important if there is some asynchronous logic inside the Effect: +Hal ini menjadi semakin penting jika terdapat beberapa logika asinkron di dalam Efek tersebut: ```js {6,8} const onVisit = useEffectEvent(visitedUrl => { @@ -701,7 +701,7 @@ This becomes especially important if there is some asynchronous logic inside the }, [url]); ``` -Here, `url` inside `onVisit` corresponds to the *latest* `url` (which could have already changed), but `visitedUrl` corresponds to the `url` that originally caused this Effect (and this `onVisit` call) to run. +Di sini, nilai `url` di dalam `onVisit` merujuk pada nilai `url` yang *terbaru* (yang mungkin sudah berubah), sedangkan `visitedUrl` merujuk pada `url` yang awalnya menyebabkan Effect ini (dan pemanggilan `onVisit` ini) dijalankan. From 075f9bf2552a07df4b307a219cf76c15129e0823 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Fri, 5 May 2023 12:52:38 +0700 Subject: [PATCH 13/22] finish deepdive --- .../learn/separating-events-from-effects.md | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index d4cc69171..0ae86ebb0 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -707,9 +707,9 @@ Di sini, nilai `url` di dalam `onVisit` merujuk pada nilai `url` yang *terbaru* -#### Is it okay to suppress the dependency linter instead? {/*is-it-okay-to-suppress-the-dependency-linter-instead*/} +#### Apakah boleh untuk tetap menonaktifkan _dependency linter_? {/*is-it-okay-to-suppress-the-dependency-linter-instead*/} -In the existing codebases, you may sometimes see the lint rule suppressed like this: +Di dalam basis kode yang sudah ada, terkadang kamu akan melihat aturan lint dinonaktifkan seperti ini: ```js {7-9} function Page({ url }) { @@ -725,13 +725,13 @@ function Page({ url }) { } ``` -After `useEffectEvent` becomes a stable part of React, we recommend **never suppressing the linter**. +Setelah `useEffectEvent` menjadi bagian versi stabil dari React, kami merekomendasikan untuk tidak menonaktifkan linter. -The first downside of suppressing the rule is that React will no longer warn you when your Effect needs to "react" to a new reactive dependency you've introduced to your code. In the earlier example, you added `url` to the dependencies *because* React reminded you to do it. You will no longer get such reminders for any future edits to that Effect if you disable the linter. This leads to bugs. +Kekurangan pertama dari menonaktifkan aturan tersebut adalah bahwa React tidak akan memberikan peringatan lagi ketika Effect yang kamu buat perlu "bereaksi" terhadap dependensi reaktif baru yang kamu tambahkan ke dalam kode. Pada contoh sebelumnya, kamu menambahkan `url` sebagai dependensi karena React mengingatkannya. Jika kamu menonaktifkan linter, secara otomatis tidak akan ada lagi pengingat yang sama untuk perubahan Effect tersebut ke depannya. Hal ini dapat menyebabkan terjadinya bug. -Here is an example of a confusing bug caused by suppressing the linter. In this example, the `handleMove` function is supposed to read the current `canMove` state variable value in order to decide whether the dot should follow the cursor. However, `canMove` is always `true` inside `handleMove`. +Berikut ini contoh dari bug yang membingungkan yang terjadi karena penonaktifan linter. Pada contoh ini, fungsi `handleMove` seharusnya membaca nilai variabel state `canMove` yang terbaru untuk menentukan apakah titik harus mengikuti kursor atau tidak. Namun, `canMove` selalu bernilai `true` di dalam `handleMove`. -Can you see why? +Apakah kamu dapat melihat penyebabnya? @@ -789,14 +789,13 @@ body { +Masalah pada kode tersebut terletak pada penonaktifan lint dependency. Jika kamu menghapus penonaktifannya, maka kamu akan melihat bahwa Effect tersebut harus membutuhkan fungsi `handleMove` sebagai dependensi. Hal ini masuk akal, karena `handleMove` dideklarasikan di dalam badan komponen, yang membuatnya menjadi sebuah nilai reaktif. Setiap nilai reaktif harus dijadikan dependensi, jika tidak, maka nilai tersebut berpotensi menjadi usang dari waktu ke waktu! -The problem with this code is in suppressing the dependency linter. If you remove the suppression, you'll see that this Effect should depend on the `handleMove` function. This makes sense: `handleMove` is declared inside the component body, which makes it a reactive value. Every reactive value must be specified as a dependency, or it can potentially get stale over time! +Penulis kode tersebut "membohongi" React dengan mengatakan bahwa Effect tersebut tidak memiliki dependensi (`[]`) pada nilai yang reaktif. Inilah yang menyebabkan React tidak mensinkronisasikan kembali Effect tersebut setelah terjadinya perubahan pada `canMove` (dan `handleMove`). Karena React tidak mensinkronisasikan kembali Effect tersebut, maka `handleMove` yang digunakan sebagai listener adalah fungsi `handleMove` yang dibuat selama render awal. Selama render awal, `canMove` bernilai `true`, itulah sebabnya fungsi `handleMove` dari render awal akan selalu melihat nilai tersebut. -The author of the original code has "lied" to React by saying that the Effect does not depend (`[]`) on any reactive values. This is why React did not re-synchronize the Effect after `canMove` has changed (and `handleMove` with it). Because React did not re-synchronize the Effect, the `handleMove` attached as a listener is the `handleMove` function created during the initial render. During the initial render, `canMove` was `true`, which is why `handleMove` from the initial render will forever see that value. +**Dengan tidak pernah menonaktifkan linter dependency, kamu tidak akan pernah mengalami masalah dengan nilai yang usang.** -**If you never suppress the linter, you will never see problems with stale values.** - -With `useEffectEvent`, there is no need to "lie" to the linter, and the code works as you would expect: +Dengan `useEffectEvent`, tidak perlu "berbohong" pada linter, dan kode dapat bekerja sesuai dengan yang kamu harapkan: @@ -870,9 +869,9 @@ body { -This doesn't mean that `useEffectEvent` is *always* the correct solution. You should only apply it to the lines of code that you don't want to be reactive. In the above sandbox, you didn't want the Effect's code to be reactive with regards to `canMove`. That's why it made sense to extract an Effect Event. +Hal ini tidak berarti bahwa `useEffectEvent` *selalu* menjadi solusi yang tepat. Kamu hanya perlu menerapkannya pada baris kode yang tidak ingin bersifat reaktif. Di dalam sandbox di atas, kamu tidak ingin kode Effect bersifat reaktif terhadap `canMove`. Itulah sebabnya masuk akal untuk mengekstrak ke Effect Event. -Read [Removing Effect Dependencies](/learn/removing-effect-dependencies) for other correct alternatives to suppressing the linter. +Baca [Menghapus dependensi Effect](/learn/removing-effect-dependencies) untuk mengetahui alternatif lain yang tepat selain menonaktifkan linter. From d5611b0ff3bd9aa1bdbe07521fa39657b4caf031 Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Fri, 5 May 2023 19:10:11 +0700 Subject: [PATCH 14/22] translate next section --- .../learn/separating-events-from-effects.md | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 0ae86ebb0..112d8fc76 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -633,7 +633,7 @@ function Page({ url }) { } ``` -Kamu menggunakan `numberOfItems` di dalam Effect, sehingga linter meminta agar kamu menambahkannya sebagai salah satu dependensi. Namun, sebenarnya kamu *tidak ingin* memanggil `logVisit` secara reaktif terhadap `numberOfItems`. Jika pengguna menambahkan barang ke dalam keranjang belanja dan `numberOfItems` berubah, ini tidak berarti bahwa pengguna telah mengunjungi kembali halaman tersebut. Dalam artian lain, melakukan *kunjungan ke halaman* adalah suatu "peristiwa (_event_)" yang terjadi pada saat tertentu. +Kita menggunakan `numberOfItems` di dalam Effect, sehingga linter meminta agar kita menambahkannya sebagai salah satu dependensi. Namun, sebenarnya kita *tidak ingin* memanggil `logVisit` secara reaktif terhadap `numberOfItems`. Jika pengguna menambahkan barang ke dalam keranjang belanja dan `numberOfItems` berubah, ini tidak berarti bahwa pengguna telah mengunjungi kembali halaman tersebut. Dalam artian lain, melakukan *kunjungan ke halaman* adalah suatu "peristiwa (_event_)" yang terjadi pada saat tertentu. Sebaiknya, pisahkan kode tersebut menjadi dua bagian: @@ -653,7 +653,7 @@ function Page({ url }) { } ``` -Di sini, `onVisit` adalah suatu Effect Event. Kode di dalamnya tidak bersifat reaktif. Oleh karena itu, kta dapat menggunakan `numberOfItems` (atau reactive value lain!) tanpa khawatir mengakibatkan kode di sekitarnya dijalankan ulang saat terjadi perubahan. +Di sini, `onVisit` adalah suatu Effect Event. Kode di dalamnya tidak bersifat reaktif. Oleh karena itu, kita dapat menggunakan `numberOfItems` (atau reactive value lain!) tanpa khawatir mengakibatkan kode di sekitarnya dijalankan ulang saat terjadi perubahan. Namun di sisi lain, Effect itu sendiri tetap bersifat reaktif. Kode di dalam Effect menggunakan prop `url`, sehingga Effect tersebut akan dijalankan ulang setelah setiap render dengan `url` yang berbeda. Hal ini pada akhirnya akan memanggil Effect Event `onVisit`. @@ -685,9 +685,9 @@ Cara tersebut memang bisa dilakukan, tetapi sebaiknya kita memasukkan nilai `url }, [url]); ``` -Karena Effect Event kita secara eksplisit "meminta" nilai `visitedUrl`, maka sekarang kita tidak dapat secara tidak sengaja menghapus `url` dari dependensi Effect tersebut. Jika kamu menghapus `url` dari dependensi (dan menyebabkan penghitungan kunjungan halaman yang berbeda terhitung sebagai satu), maka linter akan memberikan peringatan. Kamu ingin `onVisit` berperilaku reaktif terhadap `url`, sehingga daripada membaca nilai `url` dari dalam (yang tidak bersifat reaktif), kamu _pass_ nilai url *dari* dalam Effect. +Karena Effect Event kita secara eksplisit "meminta" nilai `visitedUrl`, maka sekarang kita tidak dapat secara tidak sengaja menghapus `url` dari dependensi Effect tersebut. Jika kita menghapus `url` dari dependensi (dan menyebabkan penghitungan kunjungan halaman yang berbeda terhitung sebagai satu), maka linter akan memberikan peringatan. Kita ingin `onVisit` berperilaku reaktif terhadap `url`, sehingga daripada membaca nilai `url` dari dalam (yang tidak bersifat reaktif), kita _pass_ nilai url *dari* dalam Effect. -Hal ini menjadi semakin penting jika terdapat beberapa logika asinkron di dalam Efek tersebut: +Hal ini menjadi semakin penting jika terdapat beberapa logika asinkron di dalam Effect tersebut: ```js {6,8} const onVisit = useEffectEvent(visitedUrl => { @@ -727,11 +727,11 @@ function Page({ url }) { Setelah `useEffectEvent` menjadi bagian versi stabil dari React, kami merekomendasikan untuk tidak menonaktifkan linter. -Kekurangan pertama dari menonaktifkan aturan tersebut adalah bahwa React tidak akan memberikan peringatan lagi ketika Effect yang kamu buat perlu "bereaksi" terhadap dependensi reaktif baru yang kamu tambahkan ke dalam kode. Pada contoh sebelumnya, kamu menambahkan `url` sebagai dependensi karena React mengingatkannya. Jika kamu menonaktifkan linter, secara otomatis tidak akan ada lagi pengingat yang sama untuk perubahan Effect tersebut ke depannya. Hal ini dapat menyebabkan terjadinya bug. +Kekurangan pertama dari menonaktifkan aturan tersebut adalah bahwa React tidak akan memberikan peringatan lagi ketika Effect yang kamu buat perlu "bereaksi" terhadap dependensi reaktif baru yang kita tambahkan ke dalam kode. Pada contoh sebelumnya, kita menambahkan `url` sebagai dependensi karena React mengingatkannya. Jika kita menonaktifkan linter, secara otomatis tidak akan ada lagi pengingat yang sama untuk perubahan Effect tersebut ke depannya. Hal ini dapat menyebabkan terjadinya bug. Berikut ini contoh dari bug yang membingungkan yang terjadi karena penonaktifan linter. Pada contoh ini, fungsi `handleMove` seharusnya membaca nilai variabel state `canMove` yang terbaru untuk menentukan apakah titik harus mengikuti kursor atau tidak. Namun, `canMove` selalu bernilai `true` di dalam `handleMove`. -Apakah kamu dapat melihat penyebabnya? +Apakah kamu dapat menemukan penyebabnya? @@ -761,7 +761,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + Titik bisa bergerak
setCanMove(e.target.checked)} /> - The dot is allowed to move + Titik bisa bergerak
-Hal ini tidak berarti bahwa `useEffectEvent` *selalu* menjadi solusi yang tepat. Kamu hanya perlu menerapkannya pada baris kode yang tidak ingin bersifat reaktif. Di dalam sandbox di atas, kamu tidak ingin kode Effect bersifat reaktif terhadap `canMove`. Itulah sebabnya masuk akal untuk mengekstrak ke Effect Event. +Hal ini tidak berarti bahwa `useEffectEvent` *selalu* menjadi solusi yang tepat. Kita hanya perlu menerapkannya pada baris kode yang tidak ingin bersifat reaktif. Di dalam sandbox di atas, kita tidak ingin kode Effect bersifat reaktif terhadap `canMove`. Itulah sebabnya masuk akal untuk mengekstrak ke Effect Event. Baca [Menghapus dependensi Effect](/learn/removing-effect-dependencies) untuk mengetahui alternatif lain yang tepat selain menonaktifkan linter. -### Limitations of Effect Events {/*limitations-of-effect-events*/} +### Keterbatasan Effect Event {/*limitations-of-effect-events*/} -This section describes an **experimental API that has not yet been released** in a stable version of React. +Bagian ini menjelaskan **API eksperimental yang belum dirilis** dalam versi React yang stabil. -Effect Events are very limited in how you can use them: +Effect Event memiliki keterbatasan sebagai berikut: -* **Only call them from inside Effects.** -* **Never pass them to other components or Hooks.** +* **Kita hanya bisa memanggilnya dari dalam Effect.** +* **Kita tidak boleh _pass_ Effect Event (sebagai argumen) ke komponen atau Hook lain.** -For example, don't declare and pass an Effect Event like this: +Sebagai contoh, jangan menggunakan Effect Event seperti ini: ```js {4-6,8} function Timer() { @@ -898,7 +898,7 @@ function Timer() { setCount(count + 1); }); - useTimer(onTick, 1000); // 🔴 Avoid: Passing Effect Events + useTimer(onTick, 1000); // 🔴 Hindari: Pass Effect Event return

{count}

} @@ -911,11 +911,11 @@ function useTimer(callback, delay) { return () => { clearInterval(id); }; - }, [delay, callback]); // Need to specify "callback" in dependencies + }, [delay, callback]); // Harus mendeklarasikan "callback" pada dependensi } ``` -Instead, always declare Effect Events directly next to the Effects that use them: +Sebaliknya, selalu deklarasikan Effect Event di dekat Effect yang menggunakannya: ```js {10-12,16,21} function Timer() { @@ -933,40 +933,40 @@ function useTimer(callback, delay) { useEffect(() => { const id = setInterval(() => { - onTick(); // ✅ Good: Only called locally inside an Effect + onTick(); // ✅ Bagus: Hanya dipanggil di dalam Effect }, delay); return () => { clearInterval(id); }; - }, [delay]); // No need to specify "onTick" (an Effect Event) as a dependency + }, [delay]); // Tidak perlu mendeklarasikan "onTick" (Effect Event) sebagai dependensi } ``` -Effect Events are non-reactive "pieces" of your Effect code. They should be next to the Effect using them. +Effect Event merupakan "bagian" yang tidak reaktif dari kode Effect. Effect Event harus dideklarasikan di dekat Effect yang menggunakannya. -- Event handlers run in response to specific interactions. -- Effects run whenever synchronization is needed. -- Logic inside event handlers is not reactive. -- Logic inside Effects is reactive. -- You can move non-reactive logic from Effects into Effect Events. -- Only call Effect Events from inside Effects. -- Don't pass Effect Events to other components or Hooks. +- Event handler berjalan sebagai respons terhadap interaksi tertentu. +- Effect berjalan ketika sinkronisasi diperlukan. +- Logika di dalam event handler tidak bersifat reaktif. +- Logika di dalam Effect bersifat reaktif. +- Kita dapat memindahkan logika yang tidak bersifat reaktif dari Effect ke dalam Effect Event. +- Hanya panggil Effect Event dari dalam Effect. +- Jangan _pass_ Effect Event (sebagai argumen) ke dalam komponen atau Hook lain. -#### Fix a variable that doesn't update {/*fix-a-variable-that-doesnt-update*/} +#### Memperbaiki variabel yang tidak terupdate {/*fix-a-variable-that-doesnt-update*/} -This `Timer` component keeps a `count` state variable which increases every second. The value by which it's increasing is stored in the `increment` state variable. You can control the `increment` variable with the plus and minus buttons. +Komponen `Timer` ini menyimpan variabel state `count` yang bertambah setiap satu detik. Nilai penambahan disimpan di dalam variabel state `increment`. Kamu dapat mengontrol variabel `increment` dengan tombol plus dan minus. -However, no matter how many times you click the plus button, the counter is still incremented by one every second. What's wrong with this code? Why is `increment` always equal to `1` inside the Effect's code? Find the mistake and fix it. +Namun, tidak peduli berapa kali kamu menekan tombol plus, nilai `count` selalu bertambah satu setiap satu detik. Apa yang salah dengan kode ini? Mengapa `increment` selalu sama dengan `1` di dalam kode Efek? Cari kesalahan tersebut dan perbaiki. -To fix this code, it's enough to follow the rules. +Untuk memperbaiki kode ini, hanya perlu mengikuti aturannya saja. @@ -997,7 +997,7 @@ export default function Timer() {

- Every second, increment by: + Setiap detik, nilai bertambah sebanyak: @@ -1018,10 +1018,10 @@ button { margin: 10px; } + +Sama seperti biasanya, jika kamu mencari bug di dalam Effect, mulailah dengan mencari comment yang menonaktifkan linter. -As usual, when you're looking for bugs in Effects, start by searching for linter suppressions. - -If you remove the suppression comment, React will tell you that this Effect's code depends on `increment`, but you "lied" to React by claiming that this Effect does not depend on any reactive values (`[]`). Add `increment` to the dependency array: +Jika kamu menghapus comment tersebut, React akan memberitahumu bahwa kode Effect ini bergantung pada nilai `increment`, tetapi kamu "berbohong" kepada React dengan mengatakan bahwa Effect tersebut tidak memiliki dependensi pada nilai reaktif manapun (`[]`). Tambahkan `increment` ke dalam array dependency: @@ -1049,7 +1049,7 @@ export default function Timer() {


- Every second, increment by: + Setiap detik, nilai bertambah sebanyak: @@ -1069,19 +1069,19 @@ button { margin: 10px; } -Now, when `increment` changes, React will re-synchronize your Effect, which will restart the interval. +Sekarang, ketika nilai `increment` berubah, React akan mensinkronisasi kembali Effect, dan interval akan diulang kembali. -#### Fix a freezing counter {/*fix-a-freezing-counter*/} +#### Memperbaiki counter yang hang {/*fix-a-freezing-counter*/} -This `Timer` component keeps a `count` state variable which increases every second. The value by which it's increasing is stored in the `increment` state variable, which you can control it with the plus and minus buttons. For example, try pressing the plus button nine times, and notice that the `count` now increases each second by ten rather than by one. +Komponen `Timer` ini menyimpan variabel state `count` yang bertambah setiap satu detik. Nilai penambahan disimpan di dalam variabel state `increment`, yang dapat kamu kendalikan dengan tombol plus dan minus. Sebagai contoh, coba tekan tombol plus sembilan kali, dan perhatikan jika `count` sekarang bertambah sepuluh setiap satu detik daripada satu. -There is a small issue with this user interface. You might notice that if you keep pressing the plus or minus buttons faster than once per second, the timer itself seems to pause. It only resumes after a second passes since the last time you've pressed either button. Find why this is happening, and fix the issue so that the timer ticks on *every* second without interruptions. +Ada masalah kecil dengan antarmuka pengguna ini. Kamu mungkin melihatnya, jika kamu terus menekan tombol plus atau minus lebih cepat dari sekali dalam satu detik, timer tampaknya terhenti. Timer baru akan berjalan lagi setelah satu detik berlalu sejak terakhir kali kamu menekan tombol tersebut. Temukan penyebabnya dan perbaiki masalah sehingga timer berjalan *setiap detik* tanpa jeda. -It seems like the Effect which sets up the timer "reacts" to the `increment` value. Does the line that uses the current `increment` value in order to call `setCount` really need to be reactive? +Tampaknya Effect yang mengatur timer "bereaksi" terhadap nilai `increment`. Apakah baris yang menggunakan nilai `increment` terbaru untuk memanggil `setCount` benar-benar perlu bersifat reaktif? @@ -1128,7 +1128,7 @@ export default function Timer() {


- Every second, increment by: + Setiap detik, nilai bertambah sebanyak: @@ -1150,9 +1150,9 @@ button { margin: 10px; } -The issue is that the code inside the Effect uses the `increment` state variable. Since it's a dependency of your Effect, every change to `increment` causes the Effect to re-synchronize, which causes the interval to clear. If you keep clearing the interval every time before it has a chance to fire, it will appear as if the timer has stalled. +Masalahnya adalah kode di dalam Effect menggunakan variabel state `increment`. Karena itu menjadi sebuah dependensi dari Effect-mu, setiap kali terjadi perubahan pada variabel `increment`, Effect akan tereksekusi kembali, yang menyebabkan interval tersebut terhapus. Jika kamu terus menghapus interval sebelum sempat berjalan, maka timer akan terlihat terhenti. -To solve the issue, extract an `onTick` Effect Event from the Effect: +Untuk memperbaiki masalahnya, extract ke Effect Event `onTick` dari dalam Effect-mu: @@ -1201,7 +1201,7 @@ export default function Timer() {


- Every second, increment by: + Setiap detik, nilai bertambah sebanyak: @@ -1222,17 +1222,17 @@ button { margin: 10px; } -Since `onTick` is an Effect Event, the code inside it isn't reactive. The change to `increment` does not trigger any Effects. +Karena `onTick` merupakan sebuah Effect Event, kode di dalamnya tidak bersifat reaktif. Perubahan pada `increment` tidak akan memicu Effect apapun. -#### Fix a non-adjustable delay {/*fix-a-non-adjustable-delay*/} +#### Memperbaiki waktu jeda yang tidak dapat disesuaikan {/*fix-a-non-adjustable-delay*/} -In this example, you can customize the interval delay. It's stored in a `delay` state variable which is updated by two buttons. However, even if you press the "plus 100 ms" button until the `delay` is 1000 milliseconds (that is, a second), you'll notice that the timer still increments very fast (every 100 ms). It's as if your changes to the `delay` are ignored. Find and fix the bug. +Pada contoh ini, kamu dapat menyesuaikan waktu jeda interval. Nilainya disimpan di dalam variabel state `delay` yang diperbarui oleh dua tombol. Namun, bahkan jika kamu menekan tombol "tambah 100 ms" beberapa kali sampai nilai delay menjadi 1000 milidetik (yakni satu detik), kamu akan melihat bahwa timer masih bertambah sangat cepat (setiap 100 ms). Seolah-olah perubahan dalam variabel delay diabaikan. Temukan dan perbaiki kesalahannya. -Code inside Effect Events is not reactive. Are there cases in which you would _want_ the `setInterval` call to re-run? +Kode di dalam Effect Event tidak bersifat reaktif. Apakah ada kasus di mana kamu ingin memanggil `setInterval` kembali? @@ -1288,7 +1288,7 @@ export default function Timer() {


- Increment by: + Nilai bertambah sebanyak: @@ -1298,7 +1298,7 @@ export default function Timer() { }}>+

- Increment delay: + Delay penambahan sebanyak: @@ -1321,7 +1321,7 @@ button { margin: 10px; } -The problem with the above example is that it extracted an Effect Event called `onMount` without considering what the code should actually be doing. You should only extract Effect Events for a specific reason: when you want to make a part of your code non-reactive. However, the `setInterval` call *should* be reactive with respect to the `delay` state variable. If the `delay` changes, you want to set up the interval from scratch! To fix this code, pull all the reactive code back inside the Effect: +Masalah pada contoh di atas adalah kode mengekstrak sebuah Effect Event bernama `onMount` tanpa mempertimbangkan apa yang seharusnya dilakukan oleh kode tersebut. Kamu harus hanya mengekstrak Effect Event untuk alasan tertentu: ketika ingin membuat bagian dari kodemu bersifat tak reaktif. Namun, `setInterval` memang *harus* bersifat reaktif terhadap variabel state `delay`. Jika `delay` berubah, kamu ingin menyiapkan interval tersebut kembali dari awal! Untuk memperbaiki kode ini, letakkan semua kode yang bersifat reaktif di dalam Effect: @@ -1371,7 +1371,7 @@ export default function Timer() {


- Increment by: + Nilai bertambah sebanyak: @@ -1381,7 +1381,7 @@ export default function Timer() { }}>+

- Increment delay: + Delay penambahan sebanyak: @@ -1401,7 +1401,7 @@ button { margin: 10px; } -In general, you should be suspicious of functions like `onMount` that focus on the *timing* rather than the *purpose* of a piece of code. It may feel "more descriptive" at first but it obscures your intent. As a rule of thumb, Effect Events should correspond to something that happens from the *user's* perspective. For example, `onMessage`, `onTick`, `onVisit`, or `onConnected` are good Effect Event names. Code inside them would likely not need to be reactive. On the other hand, `onMount`, `onUpdate`, `onUnmount`, or `onAfterRender` are so generic that it's easy to accidentally put code that *should* be reactive into them. This is why you should name your Effect Events after *what the user thinks has happened,* not when some code happened to run. +Pada umumnya, kamu harus meragukan fungsi seperti `onMount` yang berfokus pada *timing* daripada *tujuan* suatu dari bagian kode. Pada awalnya, hal tersebut mungkin terasa "lebih deskriptif", tetapi hal itu dapat menyembunyikan niatmu. Sebagai aturan praktis, Effect Event harus sesuai dengan sesuatu yang terjadi dari *perspektif pengguna.* Misalnya, `onMessage`, `onTick`, `onVisit`, atau `onConnected` adalah nama Effect Event yang baik. Kode di dalamnya mungkin tidak perlu bersifat reaktif. Di sisi lain, `onMount`, `onUpdate`, `onUnmount`, atau `onAfterRender` terlalu generik sehingga mudah untuk secara tidak sengaja menambahkan kode yang *harus* bersifat reaktif ke dalamnya. Oleh karena itu, kamu harus memberikan nama pada Effect Event dengan cara yang sesuai terhadap *apa yang pengguna pikirkan telah terjadi,* dan bukan pada saat kapan kode dijalankan. From af78638073c3b2555a1e06abe590edf118cbcb9c Mon Sep 17 00:00:00 2001 From: doaortu <113872927+doaortu@users.noreply.github.com> Date: Fri, 5 May 2023 19:32:37 +0700 Subject: [PATCH 15/22] finish translating --- .../learn/separating-events-from-effects.md | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index 112d8fc76..41f8c7825 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -1405,17 +1405,17 @@ Pada umumnya, kamu harus meragukan fungsi seperti `onMount` yang berfokus pada * -#### Fix a delayed notification {/*fix-a-delayed-notification*/} +#### Memperbaiki notifikasi yang terlambat {/*fix-a-delayed-notification*/} -When you join a chat room, this component shows a notification. However, it doesn't show the notification immediately. Instead, the notification is artificially delayed by two seconds so that the user has a chance to look around the UI. +Ketika kamu bergabung dengan _chat room_, komponen ini menampilkan notifikasi. Namun, notifikasi tersebut tidak ditampilkan secara langsung. Sebaliknya, notifikasi tertunda selama dua detik agar pengguna memiliki kesempatan untuk melihat-lihat UI. -This almost works, but there is a bug. Try changing the dropdown from "general" to "travel" and then to "music" very quickly. If you do it fast enough, you will see two notifications (as expected!) but they will *both* say "Welcome to music". +Ini hampir berhasil, tetapi terdapat bug. Cobalah untuk mengubah dropdown dari "general" menjadi "travel" kemudian ke "music" dengan sangat cepat. Jika kamu melakukannya dengan cepat, kamu akan melihat dua notifikasi (seperti yang diharapkan!) tetapi *keduanya* akan mengatakan "Selamat Datang di music". -Fix it so that when you switch from "general" to "travel" and then to "music" very quickly, you see two notifications, the first one being "Welcome to travel" and the second one being "Welcome to music". (For an additional challenge, assuming you've *already* made the notifications show the correct rooms, change the code so that only the latter notification is displayed.) +Perbaikilah, sehingga ketika kamu beralih dari "general" ke "travel" dan kemudian ke "music" dengan sangat cepat, kamu akan melihat dua notifikasi, yang pertama adalah "Selamat datang di travel" dan yang kedua adalah "Selamat datang di music". (Untuk tantangan tambahan, jika kamu *sudah* membuat notifikasi agar menampilkan ruangan yang tepat, ubahlah kode agar hanya notifikasi terakhir yang ditampilkan.) -Your Effect knows which room it connected to. Is there any information that you might want to pass to your Effect Event? +Effect-mu mengetahui ruangan mana yang terhubung. Adakah informasi yang mungkin ingin kamu _pass_ ke dalam Effect Event-mu? @@ -1448,7 +1448,7 @@ const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(() => { - showNotification('Welcome to ' + roomId, theme); + showNotification('Selamat datang di ' + roomId, theme); }); useEffect(() => { @@ -1462,7 +1462,7 @@ function ChatRoom({ roomId, theme }) { return () => connection.disconnect(); }, [roomId]); - return

Welcome to the {roomId} room!

+ return

Selamat datang di room {roomId}!

} export default function App() { @@ -1471,7 +1471,7 @@ export default function App() { return ( <>
-The Effect that had `roomId` set to `"travel"` (so it connected to the `"travel"` room) will show the notification for `"travel"`. The Effect that had `roomId` set to `"music"` (so it connected to the `"music"` room) will show the notification for `"music"`. In other words, `connectedRoomId` comes from your Effect (which is reactive), while `theme` always uses the latest value. +Effect yang menghubungkan ke ruangan `"travel"` (sehingga mengubah nilai `roomId` menjadi `"travel"`) akan menampilkan notifikasi untuk ruangan `"travel"`. Efek yang menghubungkan ke ruangan `"music"` (sehingga mengubah nilai `roomId` menjadi `"music"`) akan menampilkan notifikasi untuk ruangan `"music"`. Dengan kata lain, `connectedRoomId` berasal dari Effect-mu (yang bersifat reaktif), sedangkan `theme` selalu menggunakan nilai terbaru. -To solve the additional challenge, save the notification timeout ID and clear it in the cleanup function of your Effect: +Untuk menyelesaikan tantangan tambahan, simpan ID timeout notifikasi dan bersihkan di dalam fungsi cleanup Effect-mu: @@ -1726,7 +1726,7 @@ const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId, theme }) { const onConnected = useEffectEvent(connectedRoomId => { - showNotification('Welcome to ' + connectedRoomId, theme); + showNotification('Selamat Datang di ' + connectedRoomId, theme); }); useEffect(() => { @@ -1746,7 +1746,7 @@ function ChatRoom({ roomId, theme }) { }; }, [roomId]); - return

Welcome to the {roomId} room!

+ return

Selamat datang di room {roomId}!

} export default function App() { @@ -1755,7 +1755,7 @@ export default function App() { return ( <>