From e9c355474380e49e8765d6720edc17c04f76a520 Mon Sep 17 00:00:00 2001 From: Agung Prasetio Date: Wed, 10 May 2023 17:14:51 +0800 Subject: [PATCH 001/751] New Indonesian Translation: Editor Setup page (#333) Co-authored-by: agung Co-authored-by: Irfan Maulana Co-authored-by: Resi Respati Co-authored-by: RiN --- src/content/learn/editor-setup.md | 62 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/content/learn/editor-setup.md b/src/content/learn/editor-setup.md index 94dbbbaeff..96f00970d9 100644 --- a/src/content/learn/editor-setup.md +++ b/src/content/learn/editor-setup.md @@ -1,62 +1,62 @@ --- -title: Editor Setup +title: Persiapan Editor --- -A properly configured editor can make code clearer to read and faster to write. It can even help you catch bugs as you write them! If this is your first time setting up an editor or you're looking to tune up your current editor, we have a few recommendations. +Sebuah editor yang terkonfigurasi dengan baik dapat membuat kode lebih mudah dibaca dan lebih cepat ditulis. Ini bahkan dapat membantu Anda menangkap *bug* saat Anda menulisnya! Jika ini adalah pertama kalinya Anda mempersiapkan editor atau Anda ingin menyetel ulang editor Anda saat ini, kami memiliki beberapa rekomendasi. -* What the most popular editors are -* How to format your code automatically +* Apa saja editor yang paling populer +* Cara memformat kode Anda secara otomatis -## Your editor {/*your-editor*/} +## Editor Anda {/*your-editor*/} -[VS Code](https://code.visualstudio.com/) is one of the most popular editors in use today. It has a large marketplace of extensions and integrates well with popular services like GitHub. Most of the features listed below can be added to VS Code as extensions as well, making it highly configurable! +[VS Code](https://code.visualstudio.com/) adalah salah satu editor yang paling populer yang digunakan saat ini. Memiliki pasar ekstensi yang besar dan terintegrasi dengan baik dengan layanan populer seperti GitHub. Sebagian besar fitur yang tercantum di bawah ini juga dapat ditambahkan ke VS Code sebagai ekstensi, sehingga membuatnya sangat dapat dikonfigurasi! -Other popular text editors used in the React community include: +Editor teks populer lainnya yang digunakan dalam komunitas React meliputi: -* [WebStorm](https://www.jetbrains.com/webstorm/) is an integrated development environment designed specifically for JavaScript. -* [Sublime Text](https://www.sublimetext.com/) has support for JSX and TypeScript, [syntax highlighting](https://stackoverflow.com/a/70960574/458193) and autocomplete built in. -* [Vim](https://www.vim.org/) is a highly configurable text editor built to make creating and changing any kind of text very efficient. It is included as "vi" with most UNIX systems and with Apple OS X. +* [WebStorm](https://www.jetbrains.com/webstorm/) adalah lingkungan pengembangan terpadu yang dirancang khusus untuk JavaScript. +* [Sublime Text](https://www.sublimetext.com/) memiliki dukungan untuk JSX dan TypeScript, [*syntax highlighting*](https://stackoverflow.com/a/70960574/458193) dan penyelesaian otomatis yang sudah *built-in*. +* [Vim](https://www.vim.org/) adalah editor teks yang sangat dapat dikonfigurasi yang dirancang untuk membuat membuat dan mengubah jenis teks apa pun menjadi sangat efisien. Ini disertakan sebagai "vi" dengan sebagian besar sistem UNIX dan dengan Apple OS X. -## Recommended text editor features {/*recommended-text-editor-features*/} +## Fitur editor teks yang direkomendasikan {/*recommended-text-editor-features*/} -Some editors come with these features built in, but others might require adding an extension. Check to see what support your editor of choice provides to be sure! +Beberapa editor telah memiliki fitur-fitur ini secara *built-in*, tetapi yang lain mungkin memerlukan penambahan ekstensi. Periksa untuk melihat dukungan yang disediakan editor pilihan Anda untuk memastikan! ### Linting {/*linting*/} -Code linters find problems in your code as you write, helping you fix them early. [ESLint](https://eslint.org/) is a popular, open source linter for JavaScript. +*Linter* kode dapat menemukan masalah dalam kode Anda saat Anda menulis, membantu Anda memperbaikinya lebih awal. [ESLint](https://eslint.org/) adalah *linter open source* yang populer untuk JavaScript. -* [Install ESLint with the recommended configuration for React](https://www.npmjs.com/package/eslint-config-react-app) (be sure you have [Node installed!](https://nodejs.org/en/download/current/)) -* [Integrate ESLint in VSCode with the official extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) +* [Menginstal ESLint dengan konfigurasi yang direkomendasikan untuk React](https://www.npmjs.com/package/eslint-config-react-app) (pastikan Anda telah [menginstal Node!](https://nodejs.org/en/download/current/)) +* [Integrasi ESLint di VSCode dengan ekstensi resmi](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) -**Make sure that you've enabled all the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) rules for your project.** They are essential and catch the most severe bugs early. The recommended [`eslint-config-react-app`](https://www.npmjs.com/package/eslint-config-react-app) preset already includes them. +**Pastikan Anda telah mengaktifkan semua aturan [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) untuk proyek Anda.** Mereka sangat penting dan menangkap *bug* yang paling parah lebih awal. *Preset* [`eslint-config-react-app`](https://www.npmjs.com/package/eslint-config-react-app) yang direkomendasikan sudah termasuk di dalamnya. -### Formatting {/*formatting*/} +### Pemformatan {/*formatting*/} -The last thing you want to do when sharing your code with another contributor is get into an discussion about [tabs vs spaces](https://www.google.com/search?q=tabs+vs+spaces)! Fortunately, [Prettier](https://prettier.io/) will clean up your code by reformatting it to conform to preset, configurable rules. Run Prettier, and all your tabs will be converted to spaces—and your indentation, quotes, etc will also all be changed to conform to the configuration. In the ideal setup, Prettier will run when you save your file, quickly making these edits for you. +Hal terakhir yang ingin Anda lakukan saat berbagi kode Anda dengan kontributor lain adalah terlibat dalam diskusi tentang [tab vs spasi](https://www.google.com/search?q=tabs+vs+spaces)! Untungnya, [Prettier](https://prettier.io/) akan membersihkan kode Anda dengan memformat ulang sesuai dengan aturan yang telah ditentukan. Jalankan Prettier, dan semua tab Anda akan dikonversi menjadi spasi—dan indentasi, tanda kutip, dll juga akan diubah sesuai dengan konfigurasi. Dalam pengaturan yang ideal, Prettier akan berjalan saat Anda menyimpan file Anda, dengan cepat membuat perubahan ini untuk Anda. -You can install the [Prettier extension in VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) by following these steps: +Anda dapat menginstal [ekstensi Prettier di VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) dengan mengikuti langkah-langkah berikut: -1. Launch VS Code -2. Use Quick Open (press Ctrl/Cmd+P) -3. Paste in `ext install esbenp.prettier-vscode` -4. Press Enter +1. Buka VS Code +2. Gunakan *Quick Open* (tekan Ctrl/Cmd+P) +3. Tempelkan `ext install esbenp.prettier-vscode` +4. Tekan Enter -#### Formatting on save {/*formatting-on-save*/} +#### Pemformatan saat menyimpan {/*formatting-on-save*/} -Ideally, you should format your code on every save. VS Code has settings for this! +Idealnya, Anda harus memformat kode Anda setiap kali menyimpan. VS Code memiliki pengaturan untuk ini! -1. In VS Code, press `CTRL/CMD + SHIFT + P`. -2. Type "settings" -3. Hit Enter -4. In the search bar, type "format on save" -5. Be sure the "format on save" option is ticked! +1. Di VS Code, tekan `CTRL/CMD + SHIFT + P`. +2. Ketik "settings" +3. Tekan Enter +4. Di bilah pencarian, ketik "format on save" +5. Pastikan opsi "format on save" dicentang! -> If your ESLint preset has formatting rules, they may conflict with Prettier. We recommend disabling all formatting rules in your ESLint preset using [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) so that ESLint is *only* used for catching logical mistakes. If you want to enforce that files are formatted before a pull request is merged, use [`prettier --check`](https://prettier.io/docs/en/cli.html#--check) for your continuous integration. +Jika *preset* ESLint Anda memiliki aturan pemformatan, mereka mungkin akan bertentangan dengan Prettier. Kami menyarankan untuk menonaktifkan semua aturan pemformatan di *preset* ESLint Anda menggunakan [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) sehingga ESLint hanya digunakan untuk menangkap kesalahan logis. Jika Anda ingin menegakkan bahwa *file* diformat terlebih dahulu sebelum *pull request* digabungkan, gunakan [`prettier --check`](https://prettier.io/docs/en/cli.html#--check) untuk integrasi berkelanjutan Anda. From f70576cb3e3e079812cc46b45c9de9b9d23e2b39 Mon Sep 17 00:00:00 2001 From: Resi Respati Date: Wed, 10 May 2023 17:54:43 +0700 Subject: [PATCH 002/751] docs: change the link to style guide This PR changes the references to the style guide, so only the Indonesian version is used. The English version is deprecated and will soon be deleted. --- TRANSLATION.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index d15d36d86c..ba69f8e391 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -7,8 +7,7 @@ Berikut adalah panduan-panduan dasar dalam penerjemahan situs react.dev ke Bahas Semua referensi mengenai penerjemahan terletak di [bagian Wiki](https://github.com/reactjs/id.react.dev/wiki) di repositori ini. - [Glosarium](https://github.com/reactjs/id.react.dev/wiki/Glosarium) -- [Panduan Penulisan Universal](https://github.com/reactjs/id.react.dev/wiki/Panduan-Penulisan-Universal) -- [Universal Style Guide (English)](https://github.com/reactjs/id.react.dev/wiki/Universal-Style-Guide) +- [Panduan Penulisan Umum](https://github.com/reactjs/id.react.dev/wiki/Panduan-Penulisan-Umum) Apabila Anda ingin mendikusikan apapun mengenai proyek penerjemahan situs dokumentasi ini, termasuk umpan balik (*feedback*) mengenai Glosarium dan alur kerja (*workflow*), silakan ke [bagian Discussions](https://github.com/reactjs/id.react.dev/discussions). From 8b622da79ac5e89462eb7d87ab167c1920ba78f6 Mon Sep 17 00:00:00 2001 From: M Haidar Hanif Date: Thu, 11 May 2023 22:30:59 +0700 Subject: [PATCH 003/751] Translate Quick Start (#500) --- src/content/learn/index.md | 198 ++++++++++++++++++------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index b57655bc42..0491ef6949 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -1,54 +1,54 @@ --- -title: Quick Start +title: Mulai Cepat --- -Welcome to the React documentation! This page will give you an introduction to the 80% of React concepts that you will use on a daily basis. +Selamat datang di dokumentasi React! Halaman ini akan memberikan Anda pengenalan tentang 80% konsep React yang akan Anda gunakan sehari-hari. -- How to create and nest components -- How to add markup and styles -- How to display data -- How to render conditions and lists -- How to respond to events and update the screen -- How to share data between components +- Cara membuat dan menyarangkan (*nest*) komponen-komponen +- Cara menambahkan *markup* dan *styles* +- Cara menampilkan data +- Cara me-*render* kondisi dan daftar (*lists*) +- Cara merespons *events* dan memperbarui layar +- Cara berbagi data antar komponen -## Creating and nesting components {/*components*/} +## Membuat dan menyarangkan (nesting) komponen {/*components*/} -React apps are made out of *components*. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire page. +Aplikasi React dibuat dari *komponen*. Komponen adalah bagian dari UI (*user interface*, antarmuka pengguna) yang memiliki logika dan tampilan tersendiri. Sebuah komponen dapat berukuran sekecil tombol, atau sebesar seluruh halaman. -React components are JavaScript functions that return markup: +Komponen React adalah fungsi JavaScript yang mengembalikan *markup*: ```js function MyButton() { return ( - + ); } ``` -Now that you've declared `MyButton`, you can nest it into another component: +Sekarang setelah Anda mendeklarasikan `MyButton`, Anda dapat menyarangkannya ke dalam komponen lain: ```js {5} export default function MyApp() { return (
-

Welcome to my app

+

Selamat datang di aplikasi saya

); } ``` -Notice that `` starts with a capital letter. That's how you know it's a React component. React component names must always start with a capital letter, while HTML tags must be lowercase. +Perhatikan bahwa `` dimulai dengan huruf kapital. Dengan cara itulah Anda mengetahui bahwa itu adalah sebuah komponen React. Nama komponen React harus selalu dimulai dengan huruf kapital, sedangkan *tag* HTML harus menggunakan huruf kecil. -Have a look at the result: +Lihatlah hasilnya: @@ -56,7 +56,7 @@ Have a look at the result: function MyButton() { return ( ); } @@ -64,7 +64,7 @@ function MyButton() { export default function MyApp() { return (
-

Welcome to my app

+

Selamat datang di aplikasi saya

); @@ -73,49 +73,49 @@ export default function MyApp() {
-The `export default` keywords specify the main component in the file. If you're not familiar with some piece of JavaScript syntax, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) and [javascript.info](https://javascript.info/import-export) have great references. +Kata-kata kunci `export default` menentukan komponen utama di dalam berkas (*file*). Jika Anda tidak terbiasa dengan beberapa bagian dari sintaksis JavaScript, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) dan [javascript.info] (https://javascript.info/import-export) memiliki referensi yang bagus. -## Writing markup with JSX {/*writing-markup-with-jsx*/} +## Menulis markup dengan JSX {/*writing-markup-with-jsx*/} -The markup syntax you've seen above is called *JSX*. It is optional, but most React projects use JSX for its convenience. All of the [tools we recommend for local development](/learn/installation) support JSX out of the box. +Sintaksis *markup* yang Anda lihat di atas disebut dengan *JSX*. JSX ini opsional, tetapi sebagian besar proyek React menggunakan JSX untuk kenyamanannya. Semua [alat yang kami rekomendasikan untuk pengembangan lokal] (/learn/installation) mendukung JSX secara langsung. -JSX is stricter than HTML. You have to close tags like `
`. Your component also can't return multiple JSX tags. You have to wrap them into a shared parent, like a `
...
` or an empty `<>...` wrapper: +JSX lebih ketat daripada HTML. Anda harus menutup *tag* seperti `
`. Komponen Anda juga tidak boleh mengembalikan beberapa *tag* JSX. Anda harus membungkusnya menjadi induk bersama (*shared parent*), seperti `
...
` atau sebuah pembungkus kosong `<>...`: ```js {3,6} function AboutPage() { return ( <> -

About

-

Hello there.
How do you do?

+

Tentang

+

Halo.
Apa kabar?

); } ``` -If you have a lot of HTML to port to JSX, you can use an [online converter.](https://transform.tools/html-to-jsx) +Jika Anda memiliki banyak HTML untuk dipindahkan (*port*) ke JSX, Anda dapat menggunakan [konverter online.](https://transform.tools/html-to-jsx). -## Adding styles {/*adding-styles*/} +## Menambahkan styles {/*adding-styles*/} -In React, you specify a CSS class with `className`. It works the same way as the HTML [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) attribute: +Di React, Anda menentukan kelas (*class*) CSS dengan `className`. Ini bekerja dengan cara yang sama seperti atribut HTML [`class`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class): ```js ``` -Then you write the CSS rules for it in a separate CSS file: +Kemudian Anda menulis aturan CSS untuk itu di dalam berkas CSS terpisah: ```css -/* In your CSS */ +/* Di dalam CSS Anda */ .avatar { border-radius: 50%; } ``` -React does not prescribe how you add CSS files. In the simplest case, you'll add a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) tag to your HTML. If you use a build tool or a framework, consult its documentation to learn how to add a CSS file to your project. +React tidak mengatur (*prescribe*) bagaimana cara Anda menambahkan berkas CSS. Di dalam kasus yang paling sederhana, Anda akan menambahkan *tag* [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) ke HTML Anda. Jika Anda menggunakan *build tool* atau *framework*, bacalah dokumentasinya untuk mempelajari bagaimana cara menambahkan berkas CSS ke dalam proyek Anda. -## Displaying data {/*displaying-data*/} +## Menampilkan data {/*displaying-data*/} -JSX lets you put markup into JavaScript. Curly braces let you "escape back" into JavaScript so that you can embed some variable from your code and display it to the user. For example, this will display `user.name`: +JSX memungkinkan Anda memasukkan *markup* ke dalam JavaScript. Kurung kurawal (*curly braces*) memungkinkan Anda "kembali" (*escape back*) ke dalam JavaScript sehingga Anda dapat menanamkan (*embed*) beberapa variabel dari kode Anda dan menampilkannya kepada pengguna. Sebagai contoh, ini akan menampilkan `user.name`: ```js {3} return ( @@ -125,7 +125,7 @@ return ( ); ``` -You can also "escape into JavaScript" from JSX attributes, but you have to use curly braces *instead of* quotes. For example, `className="avatar"` passes the `"avatar"` string as the CSS class, but `src={user.imageUrl}` reads the JavaScript `user.imageUrl` variable value, and then passes that value as the `src` attribute: +Anda juga dapat "kembali ke JavaScript" dari atribut JSX, tetapi Anda harus menggunakan tanda kurung kurawal *daripada* tanda kutip (*quotes*). Sebagai contoh, `className="avatar"` mengoper *string* `"avatar"` sebagai kelas CSS (*CSS class*), tetapi `src={user.imageUrl}` membaca nilai variabel JavaScript `user.imageUrl`, dan kemudian mengoper nilai tersebut sebagai atribut `src`: ```js {3,4} return ( @@ -136,7 +136,7 @@ return ( ); ``` -You can put more complex expressions inside the JSX curly braces too, for example, [string concatenation](https://javascript.info/operators#string-concatenation-with-binary): +Anda dapat menaruh ekspresi yang lebih kompleks (*complex expressions*) di dalam kurung kurawal JSX juga, contohnya, [penggabungan *string*](https://javascript.info/operators#string-concatenation-with-binary) (*string concatenation*): @@ -154,7 +154,7 @@ export default function Profile() { {'Photo -In the above example, `style={{}}` is not a special syntax, but a regular `{}` object inside the `style={ }` JSX curly braces. You can use the `style` attribute when your styles depend on JavaScript variables. +Pada contoh di atas, `style={{}}` bukanlah sintaksis khusus, melainkan objek `{}` biasa di dalam kurung kurawal JSX. Anda dapat menggunakan atribut `style` ketika *styles* Anda bergantung pada variabel JavaScript. -## Conditional rendering {/*conditional-rendering*/} +## Pe-render-an secara kondisional {/*conditional-rendering*/} -In React, there is no special syntax for writing conditions. Instead, you'll use the same techniques as you use when writing regular JavaScript code. For example, you can use an [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) statement to conditionally include JSX: +Di dalam React, tidak ada sintaksis khusus untuk menulis kondisi. Sebagai gantinya, Anda akan menggunakan teknik yang sama dengan yang Anda gunakan saat menulis kode JavaScript biasa. Sebagai contoh, Anda dapat menggunakan pernyataan (*statement*) [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) untuk menyertakan JSX secara kondisional: ```js let content; @@ -197,7 +197,7 @@ return ( ); ``` -If you prefer more compact code, you can use the [conditional `?` operator.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) Unlike `if`, it works inside JSX: +Jika Anda lebih menyukai kode yang lebih ringkas, Anda dapat menggunakan [operator kondisional `?`.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) Tidak seperti `if`, operator ini bekerja di dalam JSX: ```js
@@ -209,7 +209,7 @@ If you prefer more compact code, you can use the [conditional `?` operator.](htt
``` -When you don't need the `else` branch, you can also use a shorter [logical `&&` syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): +Ketika Anda tidak membutuhkan cabang (*branch*) `lain`, Anda juga dapat menggunakan sintaksis [logika `&&` yang lebih pendek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation): ```js
@@ -217,23 +217,23 @@ When you don't need the `else` branch, you can also use a shorter [logical `&&`
``` -All of these approaches also work for conditionally specifying attributes. If you're unfamiliar with some of this JavaScript syntax, you can start by always using `if...else`. +Semua pendekatan ini juga dapat digunakan untuk menentukan atribut secara kondisional. Jika Anda tidak terbiasa dengan beberapa sintaksis JavaScript ini, Anda dapat memulai dengan selalu menggunakan `if...else`. -## Rendering lists {/*rendering-lists*/} +## Me-render daftar {/*rendering-lists*/} -You will rely on JavaScript features like [`for` loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) and the [array `map()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to render lists of components. +Anda akan mengandalkan fitur JavaScript seperti perulangan [`for`] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) dan [fungsi senarai (*array*) `map()`] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) untuk me-render daftar komponen. -For example, let's say you have an array of products: +Sebagai contoh, katakanlah Anda memiliki serangkaian (*array*) produk: ```js const products = [ - { title: 'Cabbage', id: 1 }, - { title: 'Garlic', id: 2 }, - { title: 'Apple', id: 3 }, + { title: 'Kubis', id: 1 }, + { title: 'Bawang Putih', id: 2 }, + { title: 'Apel', id: 3 }, ]; ``` -Inside your component, use the `map()` function to transform an array of products into an array of `
  • ` items: +Di dalam komponen Anda, gunakan fungsi `map()` untuk mengubah serangkaian produk menjadi serangkaian *item* `
  • `: ```js const listItems = products.map(product => @@ -247,15 +247,15 @@ return ( ); ``` -Notice how `
  • ` has a `key` attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React uses your keys to know what happened if you later insert, delete, or reorder the items. +Perhatikan bagaimana `
  • ` memiliki atribut `key`. Untuk setiap *item* dalam daftar, Anda harus mengoper *string* atau angka yang secara unik mengidentifikasi *item* tersebut di antara saudara-saudaranya (*siblings*). Biasanya, *key* harus berasal dari data Anda, seperti sebuah ID basis data (*database*). React menggunakan *key* untuk mengetahui apa yang terjadi jika Anda menyisipkan (*insert*), menghapus, atau mengurutkan ulang *item*. ```js const products = [ - { title: 'Cabbage', isFruit: false, id: 1 }, - { title: 'Garlic', isFruit: false, id: 2 }, - { title: 'Apple', isFruit: true, id: 3 }, + { title: 'Kubis', isFruit: false, id: 1 }, + { title: 'Bawang Putih', isFruit: false, id: 2 }, + { title: 'Apel', isFruit: true, id: 3 }, ]; export default function ShoppingList() { @@ -278,37 +278,37 @@ export default function ShoppingList() { -## Responding to events {/*responding-to-events*/} +## Merespon ke event {/*responding-to-events*/} -You can respond to events by declaring *event handler* functions inside your components: +Anda dapat merespon ke *event* dengan mendeklarasikan fungsi *event handler* di dalam komponen Anda: ```js {2-4,7} function MyButton() { function handleClick() { - alert('You clicked me!'); + alert('Anda mengeklik saya!'); } return ( ); } ``` -Notice how `onClick={handleClick}` has no parentheses at the end! Do not _call_ the event handler function: you only need to *pass it down*. React will call your event handler when the user clicks the button. +Perhatikan bagaimana `onClick={handleClick}` tidak memiliki tanda kurung (*parentheses*) di bagian akhir! Jangan _memanggil_ fungsi *event handler*: Anda hanya perlu *mengopernya ke bawah*. React akan memanggil *event handler* Anda ketika pengguna mengeklik tombol. -## Updating the screen {/*updating-the-screen*/} +## Memperbarui layar {/*updating-the-screen*/} -Often, you'll want your component to "remember" some information and display it. For example, maybe you want to count the number of times a button is clicked. To do this, add *state* to your component. +Sering kali, Anda ingin komponen Anda "mengingat" beberapa informasi dan menampilkannya. Sebagai contoh, mungkin Anda ingin menghitung berapa kali sebuah tombol diklik. Untuk melakukan hal ini, tambahkan *state* ke komponen Anda. -First, import [`useState`](/reference/react/useState) from React: +Pertama, impor [`useState`](/reference/react/useState) dari React: ```js import { useState } from 'react'; ``` -Now you can declare a *state variable* inside your component: +Sekarang Anda dapat mendeklarasikan *variabel state* di dalam komponen Anda: ```js function MyButton() { @@ -316,9 +316,9 @@ function MyButton() { // ... ``` -You’ll get two things from `useState`: the current state (`count`), and the function that lets you update it (`setCount`). You can give them any names, but the convention is to write `[something, setSomething]`. +Anda akan mendapatkan dua hal dari `useState`: *state* saat ini (`count`), dan fungsi yang memungkinkan Anda memperbaruinya (`setCount`). Anda dapat memberi nama apa saja, tetapi konvensi yang berlaku adalah menulis `[something, setSomething]`. -The first time the button is displayed, `count` will be `0` because you passed `0` to `useState()`. When you want to change state, call `setCount()` and pass the new value to it. Clicking this button will increment the counter: +Saat pertama kali tombol ditampilkan, `count` akan menjadi `0` karena Anda mengoper `0` ke `useState()`. Ketika Anda ingin mengubah *state*, panggil `setCount()` dan berikan nilai baru padanya. Mengeklik tombol ini akan menambah penghitung (*counter*): ```js {5} function MyButton() { @@ -330,15 +330,15 @@ function MyButton() { return ( ); } ``` -React will call your component function again. This time, `count` will be `1`. Then it will be `2`. And so on. +React akan memanggil fungsi komponen Anda lagi. Kali ini, `count` akan menjadi `1`. Kemudian akan menjadi `2`. Dan seterusnya. -If you render the same component multiple times, each will get its own state. Click each button separately: +Jika Anda me-*render* komponen yang sama beberapa kali, masing-masing akan mendapatkan *state*-nya sendiri. Klik setiap tombol secara terpisah: @@ -348,7 +348,7 @@ import { useState } from 'react'; export default function MyApp() { return (
    -

    Counters that update separately

    +

    Penghitung yang diperbarui secara terpisah

    @@ -364,7 +364,7 @@ function MyButton() { return ( ); } @@ -379,59 +379,59 @@ button {
    -Notice how each button "remembers" its own `count` state and doesn't affect other buttons. +Perhatikan bagaimana setiap tombol "mengingat" *state* `count`-nya sendiri dan tidak memengaruhi tombol lainnya. -## Using Hooks {/*using-hooks*/} +## Mengggunakan Hooks {/*using-hooks*/} -Functions starting with `use` are called *Hooks*. `useState` is a built-in Hook provided by React. You can find other built-in Hooks in the [API reference.](/reference/react) You can also write your own Hooks by combining the existing ones. +Fungsi yang dimulai dengan `use` disebut dengan *Hooks*. `useState` adalah *Hook* bawaan yang disediakan oleh React. Anda dapat menemukan *Hooks* bawaan lainnya di [referensi API.](/reference/react) Anda juga dapat menulis *Hooks* Anda sendiri dengan menggabungkan *Hooks* yang sudah ada. -Hooks are more restrictive than other functions. You can only call Hooks *at the top* of your components (or other Hooks). If you want to use `useState` in a condition or a loop, extract a new component and put it there. +*Hooks* lebih terbatas dibandingkan fungsi-fungsi lainnya. Anda hanya bisa memanggil *Hooks* *di bagian atas* komponen Anda (atau *Hooks* lainnya). Jika Anda ingin menggunakan `useState` dalam sebuah kondisi atau perulangan, ekstrak komponen baru dan letakkan di sana. -## Sharing data between components {/*sharing-data-between-components*/} +## Berbagi data antar komponen {/*sharing-data-between-components*/} -In the previous example, each `MyButton` had its own independent `count`, and when each button was clicked, only the `count` for the button clicked changed: +Pada contoh sebelumnya, setiap `MyButton` memiliki `count` tersendiri, dan ketika setiap tombol diklik, hanya `count` untuk tombol yang diklik yang berubah: - + -Initially, each `MyButton`'s `count` state is `0` +Awalnya, setiap *state* `count` `MyButton` adalah `0` - + -The first `MyButton` updates its `count` to `1` +`MyButton` pertama memperbarui `count`-nya menjadi `1` -However, often you'll need components to *share data and always update together*. +Namun, sering kali Anda memerlukan komponen untuk *berbagi data dan selalu diperbarui bersamaan*. -To make both `MyButton` components display the same `count` and update together, you need to move the state from the individual buttons "upwards" to the closest component containing all of them. +Untuk membuat kedua komponen `MyButton` menampilkan `count` yang sama dan memperbarui secara bersamaan, Anda harus memindahkan *state* dari masing-masing tombol "ke atas" ke komponen terdekat yang berisi semuanya. -In this example, it is `MyApp`: +Dalam contoh ini, adalah `MyApp`: - + -Initially, `MyApp`'s `count` state is `0` and is passed down to both children +Awalnya, *state* `count` `MyApp` adalah `0` dan dioper ke bawah ke kedua anak (*children*) - + -On click, `MyApp` updates its `count` state to `1` and passes it down to both children +Saat diklik, `MyApp` memperbarui *state* `count` menjadi `1` dan menurunkannya ke kedua anak -Now when you click either button, the `count` in `MyApp` will change, which will change both of the counts in `MyButton`. Here's how you can express this in code. +Sekarang ketika Anda mengeklik salah satu tombol, `count` di `MyApp` akan berubah, yang akan mengubah kedua hitungan di `MyButton`. Berikut adalah cara untuk mengekspresikannya di dalam kode. -First, *move the state up* from `MyButton` into `MyApp`: +Pertama, *pindahkan state ke atas* dari `MyButton` ke `MyApp`: ```js {2-6,18} export default function MyApp() { @@ -443,7 +443,7 @@ export default function MyApp() { return (
    -

    Counters that update separately

    +

    Penghitung yang diperbarui secara terpisah

    @@ -451,12 +451,12 @@ export default function MyApp() { } function MyButton() { - // ... we're moving code from here ... + // ... kita memindahkan kode dari sini ... } ``` -Then, *pass the state down* from `MyApp` to each `MyButton`, together with the shared click handler. You can pass information to `MyButton` using the JSX curly braces, just like you previously did with built-in tags like ``: +Kemudian, *oper state ke bawah* dari `MyApp` ke setiap `MyButton`, bersama dengan *shared click handler*. Anda dapat mengoper informasi ke `MyButton` menggunakan kurung kurawal JSX, seperti yang sebelumnya Anda lakukan dengan *tag* bawaan seperti ``: ```js {11-12} export default function MyApp() { @@ -476,21 +476,21 @@ export default function MyApp() { } ``` -The information you pass down like this is called _props_. Now the `MyApp` component contains the `count` state and the `handleClick` event handler, and *passes both of them down as props* to each of the buttons. +Informasi yang Anda berikan seperti ini disebut *props*. Sekarang komponen `MyApp` berisi *state* `count` dan *event handler* `handleClick`, dan *mengoper keduanya sebagai props* ke masing-masing tombol. -Finally, change `MyButton` to *read* the props you have passed from its parent component: +Terakhir, ubah `MyButton` untuk *membaca* *props* yang telah Anda lewati dari komponen induknya: ```js {1,3} function MyButton({ count, onClick }) { return ( ); } ``` -When you click the button, the `onClick` handler fires. Each button's `onClick` prop was set to the `handleClick` function inside `MyApp`, so the code inside of it runs. That code calls `setCount(count + 1)`, incrementing the `count` state variable. The new `count` value is passed as a prop to each button, so they all show the new value. This is called "lifting state up". By moving state up, you've shared it between components. +Ketika Anda mengeklik tombol, *handler* `onClick` akan dijalankan (*fires*). *Prop* `onClick` pada setiap tombol diatur ke fungsi `handleClick` di dalam `MyApp`, sehingga kode di dalamnya dapat berjalan. Kode tersebut memanggil `setCount(count + 1)`, yang menambah variabel *state* `count`. Nilai `count` yang baru dioper sebagai *prop* ke setiap tombol, sehingga semuanya menampilkan nilai yang baru. Hal ini disebut "mengangkat state ke atas" (*"lifting state up"*). Dengan mengangkat *state* ke atas, Anda telah membagikannya di antara komponen. @@ -506,7 +506,7 @@ export default function MyApp() { return (
    -

    Counters that update together

    +

    Penghitung yang diperbarui bersamaan

    @@ -516,7 +516,7 @@ export default function MyApp() { function MyButton({ count, onClick }) { return ( ); } @@ -531,8 +531,8 @@ button {
    -## Next Steps {/*next-steps*/} +## Langkah Selanjutnya {/*next-steps*/} -By now, you know the basics of how to write React code! +Sekarang, Anda telah mengetahui dasar-dasar cara menulis kode React! -Check out the [Tutorial](/learn/tutorial-tic-tac-toe) to put them into practice and build your first mini-app with React. +Lihat [Tutorial](/learn/tutorial-tic-tac-toe) untuk mempraktikkannya dan membangun aplikasi mini pertama Anda dengan React. From eec3afd822bc002918c16688a94fc2041ed54abb Mon Sep 17 00:00:00 2001 From: M Haidar Hanif Date: Fri, 12 May 2023 14:43:34 +0700 Subject: [PATCH 004/751] Fix typo on Quick Start (#561) --- src/content/learn/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 0491ef6949..01ada18950 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -381,7 +381,7 @@ button { Perhatikan bagaimana setiap tombol "mengingat" *state* `count`-nya sendiri dan tidak memengaruhi tombol lainnya. -## Mengggunakan Hooks {/*using-hooks*/} +## Menggunakan Hooks {/*using-hooks*/} Fungsi yang dimulai dengan `use` disebut dengan *Hooks*. `useState` adalah *Hook* bawaan yang disediakan oleh React. Anda dapat menemukan *Hooks* bawaan lainnya di [referensi API.](/reference/react) Anda juga dapat menulis *Hooks* Anda sendiri dengan menggabungkan *Hooks* yang sudah ada. From ebc45f563e9612df7b485ad82324225d554c625b Mon Sep 17 00:00:00 2001 From: Viacheslav Makarov <9768704+mekarthedev@users.noreply.github.com> Date: Fri, 12 May 2023 18:15:37 +0200 Subject: [PATCH 005/751] Remove unnecessary backticks breaking markdown highlighting (#6025) --- src/content/learn/removing-effect-dependencies.md | 4 ++-- src/content/learn/separating-events-from-effects.md | 6 +++--- src/content/learn/updating-objects-in-state.md | 2 +- src/content/reference/react-dom/client/createRoot.md | 4 ++-- src/content/reference/react-dom/client/hydrateRoot.md | 2 +- src/content/reference/react-dom/hydrate.md | 2 +- src/content/reference/react-dom/render.md | 2 +- src/content/reference/react-dom/unmountComponentAtNode.md | 2 +- src/content/reference/react/cloneElement.md | 2 +- src/content/reference/react/createContext.md | 2 +- src/content/reference/react/useEffect.md | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/content/learn/removing-effect-dependencies.md b/src/content/learn/removing-effect-dependencies.md index dc34eedadc..0a5151daaa 100644 --- a/src/content/learn/removing-effect-dependencies.md +++ b/src/content/learn/removing-effect-dependencies.md @@ -882,7 +882,7 @@ const options2 = { serverUrl: 'https://localhost:1234', roomId: 'music' }; // These are two different objects! console.log(Object.is(options1, options2)); // false -```` +``` **Object and function dependencies can make your Effect re-synchronize more often than you need.** @@ -968,7 +968,7 @@ const roomId2 = 'music'; // These two strings are the same! console.log(Object.is(roomId1, roomId2)); // true -```` +``` Thanks to this fix, the chat no longer re-connects if you edit the input: diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index e932e8afd0..a897a602b8 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -239,7 +239,7 @@ function ChatRoom({ roomId, 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: @@ -256,7 +256,7 @@ function ChatRoom({ roomId, theme }) { }; }, [roomId, theme]); // ✅ All dependencies declared // ... -```` +``` Play with this example and see if you can spot the problem with this user experience: @@ -416,7 +416,7 @@ function ChatRoom({ roomId, theme }) { showNotification('Connected!', 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. diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md index 1e23c8d3d5..9289f2454a 100644 --- a/src/content/learn/updating-objects-in-state.md +++ b/src/content/learn/updating-objects-in-state.md @@ -184,7 +184,7 @@ const nextPosition = {}; nextPosition.x = e.clientX; nextPosition.y = e.clientY; setPosition(nextPosition); -```` +``` In fact, it is completely equivalent to writing this: diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index 9121e1d783..d91bc20c6d 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -133,7 +133,7 @@ import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(); -```` +``` Usually, you only need to run this code once at startup. It will: @@ -395,7 +395,7 @@ root.render(App); // ✅ Correct: is a component. root.render(); -```` +``` Or if you pass a function to `root.render`, instead of the result of calling it: diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index c875560da5..db558bb807 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -127,7 +127,7 @@ If your app's HTML was generated by [`react-dom/server`](/reference/react-dom/cl import { hydrateRoot } from 'react-dom/client'; hydrateRoot(document.getElementById('root'), ); -```` +``` This will hydrate the server HTML inside the browser DOM node with the React component for your app. Usually, you will do it once at startup. If you use a framework, it might do this behind the scenes for you. diff --git a/src/content/reference/react-dom/hydrate.md b/src/content/reference/react-dom/hydrate.md index ab036caa1b..639c7ab25b 100644 --- a/src/content/reference/react-dom/hydrate.md +++ b/src/content/reference/react-dom/hydrate.md @@ -68,7 +68,7 @@ Call `hydrate` to attach a React component into a import { hydrate } from 'react-dom'; hydrate(, document.getElementById('root')); -```` +``` Using `hydrate()` to render a client-only app (an app without server-rendered HTML) is not supported. Use [`render()`](/reference/react-dom/render) (in React 17 and below) or [`createRoot()`](/reference/react-dom/client/createRoot) (in React 18+) instead. diff --git a/src/content/reference/react-dom/render.md b/src/content/reference/react-dom/render.md index 1a3baead75..a0f751278e 100644 --- a/src/content/reference/react-dom/render.md +++ b/src/content/reference/react-dom/render.md @@ -77,7 +77,7 @@ import { render } from 'react-dom'; import App from './App.js'; render(, document.getElementById('root')); -```` +``` ### Rendering the root component {/*rendering-the-root-component*/} diff --git a/src/content/reference/react-dom/unmountComponentAtNode.md b/src/content/reference/react-dom/unmountComponentAtNode.md index e538ceb343..12f11dc74d 100644 --- a/src/content/reference/react-dom/unmountComponentAtNode.md +++ b/src/content/reference/react-dom/unmountComponentAtNode.md @@ -64,7 +64,7 @@ render(, rootNode); // ... unmountComponentAtNode(rootNode); -```` +``` ### Removing a React app from a DOM element {/*removing-a-react-app-from-a-dom-element*/} diff --git a/src/content/reference/react/cloneElement.md b/src/content/reference/react/cloneElement.md index 86711f4d86..d6ef84b0a9 100644 --- a/src/content/reference/react/cloneElement.md +++ b/src/content/reference/react/cloneElement.md @@ -427,7 +427,7 @@ With this approach, `Row` does not need to receive an `isHighlighted` prop at al export default function Row({ title }) { const isHighlighted = useContext(HighlightContext); // ... -```` +``` This allows the calling component to not know or worry about passing `isHighlighted` to ``: diff --git a/src/content/reference/react/createContext.md b/src/content/reference/react/createContext.md index ff9032aac1..a653633c1d 100644 --- a/src/content/reference/react/createContext.md +++ b/src/content/reference/react/createContext.md @@ -166,7 +166,7 @@ import { createContext } from 'react'; export const ThemeContext = createContext('light'); export const AuthContext = createContext(null); -```` +``` Components declared in other files can then use the [`import`](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import) statement to read or provide this context: diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index 8614991ca2..dd84fd2ea1 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -531,7 +531,7 @@ function ChatRoom({ roomId }) { serverUrl: serverUrl }); // ... -```` +``` There are also many excellent custom Hooks for every purpose available in the React ecosystem. From e75262cdbcc7e5b5c927cefb08190c20d42be2c3 Mon Sep 17 00:00:00 2001 From: "Renova M. Reza" Date: Tue, 16 May 2023 04:41:21 +0700 Subject: [PATCH 006/751] docs: fix links not working on the Quick Start page (#560) --- src/content/learn/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/index.md b/src/content/learn/index.md index 01ada18950..00cfaecc49 100644 --- a/src/content/learn/index.md +++ b/src/content/learn/index.md @@ -73,11 +73,11 @@ export default function MyApp() { -Kata-kata kunci `export default` menentukan komponen utama di dalam berkas (*file*). Jika Anda tidak terbiasa dengan beberapa bagian dari sintaksis JavaScript, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) dan [javascript.info] (https://javascript.info/import-export) memiliki referensi yang bagus. +Kata-kata kunci `export default` menentukan komponen utama di dalam berkas (*file*). Jika Anda tidak terbiasa dengan beberapa bagian dari sintaksis JavaScript, [MDN](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) dan [javascript.info](https://javascript.info/import-export) memiliki referensi yang bagus. ## Menulis markup dengan JSX {/*writing-markup-with-jsx*/} -Sintaksis *markup* yang Anda lihat di atas disebut dengan *JSX*. JSX ini opsional, tetapi sebagian besar proyek React menggunakan JSX untuk kenyamanannya. Semua [alat yang kami rekomendasikan untuk pengembangan lokal] (/learn/installation) mendukung JSX secara langsung. +Sintaksis *markup* yang Anda lihat di atas disebut dengan *JSX*. JSX ini opsional, tetapi sebagian besar proyek React menggunakan JSX untuk kenyamanannya. Semua [alat yang kami rekomendasikan untuk pengembangan lokal](/learn/installation) mendukung JSX secara langsung. JSX lebih ketat daripada HTML. Anda harus menutup *tag* seperti `
    `. Komponen Anda juga tidak boleh mengembalikan beberapa *tag* JSX. Anda harus membungkusnya menjadi induk bersama (*shared parent*), seperti `
    ...
    ` atau sebuah pembungkus kosong `<>...`: @@ -221,7 +221,7 @@ Semua pendekatan ini juga dapat digunakan untuk menentukan atribut secara kondis ## Me-render daftar {/*rendering-lists*/} -Anda akan mengandalkan fitur JavaScript seperti perulangan [`for`] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) dan [fungsi senarai (*array*) `map()`] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) untuk me-render daftar komponen. +Anda akan mengandalkan fitur JavaScript seperti perulangan [`for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) dan [fungsi senarai (*array*) `map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) untuk me-render daftar komponen. Sebagai contoh, katakanlah Anda memiliki serangkaian (*array*) produk: From fd8ba03f4d7222ac4813374843a44755fc8c64c4 Mon Sep 17 00:00:00 2001 From: Choi siun Date: Wed, 17 May 2023 03:01:40 +0900 Subject: [PATCH 007/751] docs(types): Fix incorrect period positioning in common.md (#6040) --- src/content/reference/react-dom/components/common.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index ca16b6a6e4..b8b80ea2fd 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -156,7 +156,7 @@ nt. * [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title): A string. Specifies the tooltip text for the element. * [`translate`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/translate): Either `'yes'` or `'no'`. Passing `'no'` excludes the element content from being translated. -You can also pass custom attributes as props, for example `mycustomprop="someValue".` This can be useful when integrating with third-party libraries. The custom attribute name must be lowercase and must not start with `on`. The value will be converted to a string. If you pass `null` or `undefined`, the custom attribute will be removed. +You can also pass custom attributes as props, for example `mycustomprop="someValue"`. This can be useful when integrating with third-party libraries. The custom attribute name must be lowercase and must not start with `on`. The value will be converted to a string. If you pass `null` or `undefined`, the custom attribute will be removed. These events fire only for the [`
    `](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) elements: From bea2ff778d489eb0401eef173a3b7bf74563930e Mon Sep 17 00:00:00 2001 From: vicsantizo <68677648+vicsantizo@users.noreply.github.com> Date: Tue, 16 May 2023 12:01:59 -0600 Subject: [PATCH 008/751] fix(typos): replace word "ever" with "every" (#6039) --- src/content/reference/react-dom/components/common.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index b8b80ea2fd..f1e4fcd0c5 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -260,7 +260,7 @@ React will also call your `ref` callback whenever you pass a *different* `ref` c #### Parameters {/*ref-callback-parameters*/} -* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the ref gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during ever re-render of the component. +* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the ref gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component. #### Returns {/*returns*/} From 42e951eed3c56733ec4ac0b6454181049a1185e6 Mon Sep 17 00:00:00 2001 From: Ravinda Putra <49386664+rvndaputra@users.noreply.github.com> Date: Thu, 18 May 2023 01:22:54 +0700 Subject: [PATCH 009/751] docs: translation for reusing logic with custom hooks (#363) --- .../learn/reusing-logic-with-custom-hooks.md | 355 +++++++++--------- 1 file changed, 177 insertions(+), 178 deletions(-) diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md index 679a9bac21..a12ec0e4c4 100644 --- a/src/content/learn/reusing-logic-with-custom-hooks.md +++ b/src/content/learn/reusing-logic-with-custom-hooks.md @@ -1,30 +1,30 @@ --- -title: 'Reusing Logic with Custom Hooks' +title: 'Menggunakan ulang logika dengan Custom Hooks' --- -React comes with several built-in Hooks like `useState`, `useContext`, and `useEffect`. Sometimes, you'll wish that there was a Hook for some more specific purpose: for example, to fetch data, to keep track of whether the user is online, or to connect to a chat room. You might not find these Hooks in React, but you can create your own Hooks for your application's needs. +React dilengkapi dengan beberapa Hook bawaan seperti `useState`, `useContext`, dan `useEffect`. Terkadang, Anda mungkin ingin ada Hook untuk tujuan yang lebih spesifik: misalnya, untuk mengambil data, melacak apakah pengguna sedang online, atau terhubung ke ruang obrolan. Anda mungkin tidak menemukan Hook ini di React, tetapi Anda dapat membuat Hook Anda sendiri untuk kebutuhan aplikasi Anda. -- What custom Hooks are, and how to write your own -- How to reuse logic between components -- How to name and structure your custom Hooks -- When and why to extract custom Hooks +- Apa itu custom Hooks, dan bagaimana menulis Hooks sendiri +- Bagaimana cara menggunakan ulang logika antara komponen +- Bagaimana memberi nama dan mengatur struktur Hooks yang dibuat sendiri +- Kapan dan mengapa harus mengekstrak custom Hooks -## Custom Hooks: Sharing logic between components {/*custom-hooks-sharing-logic-between-components*/} +## Custom Hooks: Berbagi logika antar komponen {/*custom-hooks-sharing-logic-between-components*/} -Imagine you're developing an app that heavily relies on the network (as most apps do). You want to warn the user if their network connection has accidentally gone off while they were using your app. How would you go about it? It seems like you'll need two things in your component: +Bayangkan Anda sedang mengembangkan aplikasi yang sangat bergantung pada jaringan (seperti kebanyakan aplikasi). Anda ingin memberi peringatan kepada pengguna jika koneksi jaringannya tiba-tiba terputus saat mereka menggunakan aplikasi Anda. Bagaimana cara melakukannya? Sepertinya Anda akan memerlukan dua hal dalam komponen Anda: -1. A piece of state that tracks whether the network is online. -2. An Effect that subscribes to the global [`online`](https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event) and [`offline`](https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event) events, and updates that state. +1. Sebuah keadaan (state) yang melacak apakah jaringan online. +2. Sebuah Efek yang berlangganan (subscribes) pada peristiwa (events) [`online`](https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event) dan [`offline`](https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event) global, dan memperbarui state tersebut. -This will keep your component [synchronized](/learn/synchronizing-with-effects) with the network status. You might start with something like this: +Hal ini akan menjaga [sinkronisasi](/learn/synchronizing-with-effects) komponen Anda dengan status jaringan. Anda mungkin memulainya dengan sesuatu seperti ini: @@ -54,11 +54,11 @@ export default function StatusBar() { -Try turning your network on and off, and notice how this `StatusBar` updates in response to your actions. +Coba matikan dan nyalakan jaringan Anda, dan perhatikan bagaimana `StatusBar` ini diperbarui sebagai respons terhadap tindakan Anda. -Now imagine you *also* want to use the same logic in a different component. You want to implement a Save button that will become disabled and show "Reconnecting..." instead of "Save" while the network is off. +Sekarang bayangkan Anda *juga* ingin menggunakan logika yang sama pada komponen yang berbeda. Anda ingin mengimplementasikan tombol Simpan yang akan menjadi tidak aktif dan menunjukkan "Sedang menghubungkan kembali..." alih-alih "Simpan" saat jaringan mati. -To start, you can copy and paste the `isOnline` state and the Effect into `SaveButton`: +Untuk memulai, Anda dapat menyalin dan mem-paste state `isOnline` dan Efeknya ke dalam `SaveButton`: @@ -96,13 +96,13 @@ export default function SaveButton() { -Verify that, if you turn off the network, the button will change its appearance. +Pastikan, jika Anda mematikan jaringan, tampilan tombol tersebut akan berubah. -These two components work fine, but the duplication in logic between them is unfortunate. It seems like even though they have different *visual appearance,* you want to reuse the logic between them. +Kedua komponen ini berfungsi dengan baik, tetapi duplikasi logika di antara keduanya tidak diinginkan. Meskipun mereka memiliki *tampilan visual* yang berbeda, Anda ingin menggunakan kembali logika yang sama di antara keduanya. -### Extracting your own custom Hook from a component {/*extracting-your-own-custom-hook-from-a-component*/} +### Mengekstrak custom Hook Anda sendiri dari sebuah komponen {/*extracting-your-own-custom-hook-from-a-component*/} -Imagine for a moment that, similar to [`useState`](/reference/react/useState) and [`useEffect`](/reference/react/useEffect), there was a built-in `useOnlineStatus` Hook. Then both of these components could be simplified and you could remove the duplication between them: +Bayangkan bahwa, serupa dengan [`useState`](/reference/react/useState) dan [`useEffect`](/reference/react/useEffect), ada sebuah Hook `useOnlineStatus` bawaan. Kemudian kedua komponen ini bisa disederhanakan dan Anda dapat menghapus duplikasi di antara keduanya: ```js {2,7} function StatusBar() { @@ -124,8 +124,7 @@ function SaveButton() { ); } ``` - -Although there is no such built-in Hook, you can write it yourself. Declare a function called `useOnlineStatus` and move all the duplicated code into it from the components you wrote earlier: +Meskipun tidak ada Hook bawaan seperti itu, Anda dapat menulisnya sendiri. Deklarasikan fungsi bernama `useOnlineStatus` dan pindahkan semua kode duplikat ke dalamnya dari komponen yang Anda tulis sebelumnya: ```js {2-16} function useOnlineStatus() { @@ -148,7 +147,7 @@ function useOnlineStatus() { } ``` -At the end of the function, return `isOnline`. This lets your components read that value: +Di akhir fungsi, kembalikan `isOnline`. Ini memungkinkan komponen Anda membaca nilai itu: @@ -209,89 +208,89 @@ export function useOnlineStatus() { -Verify that switching the network on and off updates both components. +Pastikan bahwa mengubah jaringan on dan off memperbarui kedua komponen. -Now your components don't have as much repetitive logic. **More importantly, the code inside them describes *what they want to do* (use the online status!) rather than *how to do it* (by subscribing to the browser events).** +Sekarang komponen Anda tidak memiliki logika berulang. **Lebih penting lagi, kode di dalamnya menjelaskan *apa yang ingin mereka lakukan* (gunakan status online!) daripada *bagaimana melakukannya* (dengan berlangganan events browser).** -When you extract logic into custom Hooks, you can hide the gnarly details of how you deal with some external system or a browser API. The code of your components expresses your intent, not the implementation. +Ketika Anda mengekstrak logika ke dalam custom Hooks, Anda dapat menyembunyikan detail-detail rumit tentang bagaimana Anda menangani sistem eksternal atau API browser. Kode komponen Anda mengekspresikan niat Anda, bukan implementasi. -### Hook names always start with `use` {/*hook-names-always-start-with-use*/} +### Nama hook selalu diawali dengan `use` {/*hook-names-always-start-with-use*/} -React applications are built from components. Components are built from Hooks, whether built-in or custom. You'll likely often use custom Hooks created by others, but occasionally you might write one yourself! +Aplikasi React dibangun dari komponen. Komponen dibuat dari Hooks, baik bawaan maupun kustom. Anda mungkin akan sering menggunakan Hooks khusus yang dibuat oleh orang lain, tetapi kadang-kadang Anda mungkin menulisnya sendiri! -You must follow these naming conventions: +Anda harus mengikuti konvensi penamaan ini: -1. **React component names must start with a capital letter,** like `StatusBar` and `SaveButton`. React components also need to return something that React knows how to display, like a piece of JSX. -2. **Hook names must start with `use` followed by a capital letter,** like [`useState`](/reference/react/useState) (built-in) or `useOnlineStatus` (custom, like earlier on the page). Hooks may return arbitrary values. +1. **Nama komponen React harus dimulai dengan huruf kapital,** seperti `StatusBar` dan `SaveButton`. Komponen React juga perlu mengembalikan sesuatu yang dapat ditampilkan oleh React, seperti sebuah potongan JSX. +2. **Nama hook harus dimulai dengan `use` diikuti dengan huruf kapital,** seperti [`useState`](/reference/react/useState) (bawaan) atau `useOnlineStatus` (kustom, seperti yang ditunjukkan pada contoh sebelumnya). Hooks dapat mengembalikan nilai arbitrer. -This convention guarantees that you can always look at a component and know where its state, Effects, and other React features might "hide". For example, if you see a `getColor()` function call inside your component, you can be sure that it can't possibly contain React state inside because its name doesn't start with `use`. However, a function call like `useOnlineStatus()` will most likely contain calls to other Hooks inside! +Konvensi ini menjamin bahwa Anda selalu dapat melihat sebuah komponen dan mengetahui di mana letak state, Efek, dan fitur React lainnya mungkin "bersembunyi". Misalnya, jika Anda melihat sebuah panggilan fungsi `getColor()` di dalam komponen Anda, Anda bisa yakin bahwa panggilan itu tidak mungkin mengandung state React di dalamnya karena namanya tidak dimulai dengan `use`. Namun, sebuah panggilan fungsi seperti `useOnlineStatus()` kemungkinan besar akan mengandung panggilan Hook lain di dalamnya! -If your linter is [configured for React,](/learn/editor-setup#linting) it will enforce this naming convention. Scroll up to the sandbox above and rename `useOnlineStatus` to `getOnlineStatus`. Notice that the linter won't allow you to call `useState` or `useEffect` inside of it anymore. Only Hooks and components can call other Hooks! +Jika linter Anda [dikonfigurasi untuk React,](/learn/editor-setup#linting) maka linter akan memberlakukan konvensi penamaan ini. Gulir ke atas ke sandbox di atas dan ganti nama `useOnlineStatus` menjadi `getOnlineStatus`. Perhatikan bahwa linter tidak mengizinkan Anda memanggil `useState` atau `useEffect` di dalamnya lagi. Hanya Hook dan komponen saja yang dapat memanggil Hook lainnya! -#### Should all functions called during rendering start with the use prefix? {/*should-all-functions-called-during-rendering-start-with-the-use-prefix*/} +#### Apakah semua fungsi yang dipanggil selama rendering harus diawali dengan awalan use? {/*should-all-functions-called-during-rendering-start-with-the-use-prefix*/} -No. Functions that don't *call* Hooks don't need to *be* Hooks. +Tidak. Fungsi yang tidak *memanggil* Hooks tidak perlu *menjadi* Hooks. -If your function doesn't call any Hooks, avoid the `use` prefix. Instead, write it as a regular function *without* the `use` prefix. For example, `useSorted` below doesn't call Hooks, so call it `getSorted` instead: +Jika fungsi Anda tidak memanggil Hooks apapun, hindari awalan `use`. Sebagai gantinya, tulislah sebagai fungsi biasa *tanpa* awalan `use`. Misalnya, `useSorted` di bawah ini tidak memanggil Hooks, jadi panggil saja `getSorted`: ```js -// 🔴 Avoid: A Hook that doesn't use Hooks +// 🔴 Hindari: Sebuah Hook yang tidak menggunakan Hooks function useSorted(items) { return items.slice().sort(); } -// ✅ Good: A regular function that doesn't use Hooks +// ✅ Baik: Sebuah fungsi biasa yang tidak menggunakan Hooks function getSorted(items) { return items.slice().sort(); } ``` -This ensures that your code can call this regular function anywhere, including conditions: +Ini memastikan bahwa kode Anda dapat memanggil fungsi biasa ini di mana saja, termasuk pada sebuah kondisi: ```js function List({ items, shouldSort }) { let displayedItems = items; if (shouldSort) { - // ✅ It's ok to call getSorted() conditionally because it's not a Hook + // ✅ Tidak apa-apa untuk memanggil getSorted() secara kondisional karena ini bukan sebuah Hook displayedItems = getSorted(items); } // ... } ``` -You should give `use` prefix to a function (and thus make it a Hook) if it uses at least one Hook inside of it: +Anda harus memberikan awalan `use` ke sebuah fungsi (dan dengan demikian menjadikannya sebuah Hook) jika fungsi tersebut menggunakan setidaknya satu Hook di dalamnya: ```js -// ✅ Good: A Hook that uses other Hooks +// ✅ Baik: Sebuah Hook yang menggunakan Hook lainnya function useAuth() { return useContext(Auth); } ``` -Technically, this isn't enforced by React. In principle, you could make a Hook that doesn't call other Hooks. This is often confusing and limiting so it's best to avoid that pattern. However, there may be rare cases where it is helpful. For example, maybe your function doesn't use any Hooks right now, but you plan to add some Hook calls to it in the future. Then it makes sense to name it with the `use` prefix: +Secara teknis, ini tidak diberlakukan oleh React. Pada prinsipnya, Anda dapat membuat sebuah Hook yang tidak memanggil Hook lain. Ini seringkali membingungkan dan membatasi jadi sebaiknya hindari pola itu. Namun, mungkin ada kasus yang jarang terjadi di mana itu sangat membantu. Misalnya, mungkin fungsi Anda tidak menggunakan Hooks saat ini, tetapi Anda berencana untuk menambahkan beberapa panggilan Hooks ke dalamnya di masa mendatang. Maka masuk akal untuk menamainya dengan awalan `use`: ```js {3-4} -// ✅ Good: A Hook that will likely use some other Hooks later +// ✅ Baik: Sebuah Hook yang kemungkinan akan menggunakan beberapa Hook lainnya nanti function useAuth() { - // TODO: Replace with this line when authentication is implemented: + // TODO: Ganti dengan baris ini saat autentikasi diterapkan: // return useContext(Auth); return TEST_USER; } ``` -Then components won't be able to call it conditionally. This will become important when you actually add Hook calls inside. If you don't plan to use Hooks inside it (now or later), don't make it a Hook. +Maka komponen tidak akan dapat memanggilnya secara kondisional. Ini akan menjadi penting ketika Anda benar-benar menambahkan panggilan Hook di dalamnya. Jika Anda tidak berencana untuk menggunakan Hooks di dalamnya (sekarang atau nanti), jangan menjadikannya sebagai Hook. -### Custom Hooks let you share stateful logic, not state itself {/*custom-hooks-let-you-share-stateful-logic-not-state-itself*/} +### Custom Hooks memungkinkan Anda berbagi logika yang berkelanjutan, bukan state itu sendiri {/*custom-hooks-let-you-share-stateful-logic-not-state-itself*/} -In the earlier example, when you turned the network on and off, both components updated together. However, it's wrong to think that a single `isOnline` state variable is shared between them. Look at this code: +Pada contoh sebelumnya, ketika Anda menghidupkan dan mematikan jaringan, kedua komponen diperbarui secara bersamaan. Namun, salah jika berpikir bahwa satu variabel state `isOnline` dibagikan di antara keduanya. Lihat kode ini: ```js {2,7} function StatusBar() { @@ -305,7 +304,7 @@ function SaveButton() { } ``` -It works the same way as before you extracted the duplication: +Ini bekerja dengan cara yang sama seperti sebelumnya sebelum duplikasi diekstrak: ```js {2-5,10-13} function StatusBar() { @@ -325,9 +324,9 @@ function SaveButton() { } ``` -These are two completely independent state variables and Effects! They happened to have the same value at the same time because you synchronized them with the same external value (whether the network is on). +Ini adalah dua variabel state dan Efek yang sepenuhnya independen! Mereka kebetulan memiliki nilai yang sama pada saat yang sama karena Anda menyinkronkannya dengan nilai eksternal yang sama (apakah jaringan sedang hidup). -To better illustrate this, we'll need a different example. Consider this `Form` component: +Untuk menggambarkan hal ini dengan lebih baik, kita memerlukan contoh yang berbeda. Pertimbangkan komponen `Form` ini: @@ -369,13 +368,13 @@ input { margin-left: 10px; } -There's some repetitive logic for each form field: +Ada beberapa logika yang berulang untuk setiap kolom formulir: -1. There's a piece of state (`firstName` and `lastName`). -1. There's a change handler (`handleFirstNameChange` and `handleLastNameChange`). -1. There's a piece of JSX that specifies the `value` and `onChange` attributes for that input. +1. Ada sebuah state (`firstName` dan `lastName`). +2. Ada handler perubahan (`handleFirstNameChange` dan `handleLastNameChange`). +3. Ada JSX yang menentukan atribut `value` dan `onChange` untuk input tersebut. -You can extract the repetitive logic into this `useFormInput` custom Hook: +Anda dapat mengekstrak logika yang berulang ke dalam Custom Hook `useFormInput` ini: @@ -428,9 +427,9 @@ input { margin-left: 10px; } -Notice that it only declares *one* state variable called `value`. +Perhatikan bahwa itu hanya mendeklarasikan *satu* variabel state yang disebut `value`. -However, the `Form` component calls `useFormInput` *two times:* +Namun, komponen `Form` memanggil `useFormInput` *dua kali:* ```js function Form() { @@ -439,17 +438,17 @@ function Form() { // ... ``` -This is why it works like declaring two separate state variables! +Inilah sebabnya mengapa itu bekerja seperti mendeklarasikan dua variabel state yang terpisah! -**Custom Hooks let you share *stateful logic* but not *state itself.* Each call to a Hook is completely independent from every other call to the same Hook.** This is why the two sandboxes above are completely equivalent. If you'd like, scroll back up and compare them. The behavior before and after extracting a custom Hook is identical. +**Custom Hooks memungkinkan Anda berbagi *logika berkelanjutan* tetapi tidak *state itu sendiri.* Setiap panggilan Hook sepenuhnya independen dari setiap panggilan ke Hook yang sama.** Inilah mengapa kedua sandbox di atas sepenuhnya setara. Jika Anda mau, gulir ke atas dan bandingkan. Perilaku sebelum dan sesudah mengekstrak Custom Hook itu identik. -When you need to share the state itself between multiple components, [lift it up and pass it down](/learn/sharing-state-between-components) instead. +Ketika Anda perlu membagikan state itu sendiri antara beberapa komponen, [angkat dan lewatkan ke bawah](/learn/sharing-state-between-components) sebagai gantinya. -## Passing reactive values between Hooks {/*passing-reactive-values-between-hooks*/} +## Mengirimkan nilai reaktif antara Hooks {/*passing-reactive-values-between-hooks*/} -The code inside your custom Hooks will re-run during every re-render of your component. This is why, like components, custom Hooks [need to be pure.](/learn/keeping-components-pure) Think of custom Hooks' code as part of your component's body! +Kode di dalam kustom Hooks akan dijalankan kembali setiap kali komponen Anda di-*render* ulang. Oleh karena itu, seperti halnya komponen, Custom Hooks [harus bersifat murni.](/learn/keeping-components-pure) Bayangkan kode kustom Hooks sebagai bagian dari badan komponen Anda! -Because custom Hooks re-render together with your component, they always receive the latest props and state. To see what this means, consider this chat room example. Change the server URL or the chat room: +Karena Custom Hooks di-*render* ulang bersama komponen Anda, mereka selalu menerima prop dan state terbaru. Untuk mengetahui apa artinya, pertimbangkan contoh ruang obrolan ini. Ubah URL server atau ruang obrolannya: @@ -516,7 +515,7 @@ export default function ChatRoom({ roomId }) { ```js chat.js export function createConnection({ serverUrl, roomId }) { - // A real implementation would actually connect to the server + //! A real implementation would actually connect to the server if (typeof serverUrl !== 'string') { throw Error('Expected serverUrl to be a string. Received: ' + serverUrl); } @@ -599,9 +598,9 @@ button { margin-left: 10px; } -When you change `serverUrl` or `roomId`, the Effect ["reacts" to your changes](/learn/lifecycle-of-reactive-effects#effects-react-to-reactive-values) and re-synchronizes. You can tell by the console messages that the chat re-connects every time that you change your Effect's dependencies. +Ketika Anda mengubah `serverUrl` atau `roomId`, Effect ["bereaksi" terhadap perubahan Anda](/learn/lifecycle-of-reactive-effects#effects-react-to-reactive-values) dan disinkronkan ulang. Anda dapat mengetahui dari pesan konsol bahwa obrolan terhubung kembali setiap kali Anda mengubah dependensi Effect Anda. -Now move the Effect's code into a custom Hook: +Sekarang pindahkan kode Effect ke dalam Custom Hook: ```js {2-13} export function useChatRoom({ serverUrl, roomId }) { @@ -620,7 +619,7 @@ export function useChatRoom({ serverUrl, roomId }) { } ``` -This lets your `ChatRoom` component call your custom Hook without worrying about how it works inside: +Ini memungkinkan komponen `ChatRoom` Anda memanggil Custom Hook tanpa perlu mengkhawatirkan cara kerjanya di dalam: ```js {4-7} export default function ChatRoom({ roomId }) { @@ -643,9 +642,9 @@ export default function ChatRoom({ roomId }) { } ``` -This looks much simpler! (But it does the same thing.) +Ini terlihat jauh lebih sederhana! (Tapi tetap melakukan hal yang sama.) -Notice that the logic *still responds* to prop and state changes. Try editing the server URL or the selected room: +Perhatikan bahwa logika *tetap merespon* perubahan prop dan state. Coba edit URL server atau ruang yang dipilih: @@ -724,7 +723,7 @@ export function useChatRoom({ serverUrl, roomId }) { ```js chat.js export function createConnection({ serverUrl, roomId }) { - // A real implementation would actually connect to the server + //! A real implementation would actually connect to the server if (typeof serverUrl !== 'string') { throw Error('Expected serverUrl to be a string. Received: ' + serverUrl); } @@ -807,7 +806,7 @@ button { margin-left: 10px; } -Notice how you're taking the return value of one Hook: +Perhatikan bagaimana Anda mengambil nilai pengembalian dari satu Hook: ```js {2} export default function ChatRoom({ roomId }) { @@ -820,7 +819,7 @@ export default function ChatRoom({ roomId }) { // ... ``` -and pass it as an input to another Hook: +dan meneruskannya sebagai masukan ke Hook lain: ```js {6} export default function ChatRoom({ roomId }) { @@ -833,17 +832,17 @@ export default function ChatRoom({ roomId }) { // ... ``` -Every time your `ChatRoom` component re-renders, it passes the latest `roomId` and `serverUrl` to your Hook. This is why your Effect re-connects to the chat whenever their values are different after a re-render. (If you ever worked with audio or video processing software, chaining Hooks like this might remind you of chaining visual or audio effects. It's as if the output of `useState` "feeds into" the input of the `useChatRoom`.) +Setiap kali komponen `ChatRoom` Anda di-*render* ulang, komponen `roomId` dan `serverUrl` terbaru diteruskan ke Hook Anda. Inilah sebabnya Effect Anda terhubung kembali ke obrolan setiap kali nilainya berbeda setelah render ulang. (Jika Anda pernah bekerja dengan perangkat lunak pemrosesan audio atau video, merantai Hooks seperti ini mungkin mengingatkan Anda pada efek visual atau audio yang saling terkait. Seolah-olah output dari `useState` "diumpankan ke dalam" input dari `useChatRoom`.) ### Passing event handlers to custom Hooks {/*passing-event-handlers-to-custom-hooks*/} -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** di versi stabil React. -As you start using `useChatRoom` in more components, you might want to let components customize its behavior. For example, currently, the logic for what to do when a message arrives is hardcoded inside the Hook: +Saat Anda mulai menggunakan `useChatRoom` di lebih banyak komponen, Anda mungkin ingin membiarkan komponen menyesuaikan perilakunya. Sebagai contoh, saat ini, logika tentang apa yang harus dilakukan ketika sebuah pesan datang di-hardcode di dalam Hook: ```js {9-11} export function useChatRoom({ serverUrl, roomId }) { @@ -862,7 +861,7 @@ export function useChatRoom({ serverUrl, roomId }) { } ``` -Let's say you want to move this logic back to your component: +Katakanlah Anda ingin memindahkan logika ini kembali ke komponen Anda: ```js {7-9} export default function ChatRoom({ roomId }) { @@ -878,7 +877,7 @@ export default function ChatRoom({ roomId }) { // ... ``` -To make this work, change your custom Hook to take `onReceiveMessage` as one of its named options: +Untuk membuatnya berfungsi, ubah custom Hook Anda untuk menerima `onReceiveMessage` sebagai salah satu opsi bernama: ```js {1,10,13} export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { @@ -897,9 +896,9 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { } ``` -This will work, but there's one more improvement you can do when your custom Hook accepts event handlers. +Ini akan berhasil, tetapi ada satu peningkatan lagi yang dapat Anda lakukan ketika custom Hook Anda menerima event handler. -Adding a dependency on `onReceiveMessage` is not ideal because it will cause the chat to re-connect every time the component re-renders. [Wrap this event handler into an Effect Event to remove it from the dependencies:](/learn/removing-effect-dependencies#wrapping-an-event-handler-from-the-props) +Menambahkan dependensi pada `onReceiveMessage` tidak ideal karena akan menyebabkan chat terhubung kembali setiap kali komponen di-*render* ulang. [Bungkus event handler ini ke dalam Effect Event untuk menghapusnya dari dependensi:](/learn/removing-effect-dependencies#wrapping-an-event-handler-from-the-props) ```js {1,4,5,15,18} import { useEffect, useEffectEvent } from 'react'; @@ -919,11 +918,11 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { onMessage(msg); }); return () => connection.disconnect(); - }, [roomId, serverUrl]); // ✅ All dependencies declared + }, [roomId, serverUrl]); // ✅ Semua dependensi dideklarasikan } ``` -Now the chat won't re-connect every time that the `ChatRoom` component re-renders. Here is a fully working demo of passing an event handler to a custom Hook that you can play with: +Sekarang obrolan tidak akan terhubung kembali setiap kali komponen `ChatRoom` di-*render* ulang. Berikut adalah demo yang berfungsi penuh untuk meneruskan event handler ke custom Hook yang dapat Anda mainkan: @@ -1008,7 +1007,7 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) { ```js chat.js export function createConnection({ serverUrl, roomId }) { - // A real implementation would actually connect to the server + // Implementasi yang sebenarnya akan terhubung ke server if (typeof serverUrl !== 'string') { throw Error('Expected serverUrl to be a string. Received: ' + serverUrl); } @@ -1091,20 +1090,20 @@ button { margin-left: 10px; } -Notice how you no longer need to know *how* `useChatRoom` works in order to use it. You could add it to any other component, pass any other options, and it would work the same way. That's the power of custom Hooks. +Perhatikan bagaimana Anda tidak perlu lagi mengetahui *bagaimana* `useChatRoom` berfungsi untuk menggunakannya. Anda bisa menambahkannya ke komponen lain, meneruskan opsi lain, dan itu akan bekerja dengan cara yang sama. Itulah kekuatan custom Hooks. -## When to use custom Hooks {/*when-to-use-custom-hooks*/} +## Kapan menggunakan custom Hooks {/*when-to-use-custom-hooks*/} -You don't need to extract a custom Hook for every little duplicated bit of code. Some duplication is fine. For example, extracting a `useFormInput` Hook to wrap a single `useState` call like earlier is probably unnecessary. +Anda tidak perlu mengekstrak custom Hook untuk setiap bit kode yang duplikat. Beberapa duplikasi memang diperbolehkan. Misalnya, mengekstrak Hook `useFormInput` untuk membungkus satu panggilan `useState` seperti sebelumnya mungkin tidak diperlukan. -However, whenever you write an Effect, consider whether it would be clearer to also wrap it in a custom Hook. [You shouldn't need Effects very often,](/learn/you-might-not-need-an-effect) so if you're writing one, it means that you need to "step outside React" to synchronize with some external system or to do something that React doesn't have a built-in API for. Wrapping it into a custom Hook lets you precisely communicate your intent and how the data flows through it. +Namun, kapan pun Anda menulis sebuah Effect, pertimbangkan apakah akan lebih jelas untuk juga membungkusnya dalam sebuah custom Hook. [Anda seharusnya tidak terlalu sering menggunakan Effect,](/learn/you-might-not-need-an-effect) jadi jika Anda menulisnya, itu berarti Anda perlu "keluar dari React" untuk menyinkronkan dengan beberapa sistem eksternal atau untuk melakukan sesuatu yang tidak memiliki API bawaan di React. Membungkusnya menjadi custom Hook memungkinkan Anda mengomunikasikan maksud Anda dengan tepat dan bagaimana data mengalir melewatinya. -For example, consider a `ShippingForm` component that displays two dropdowns: one shows the list of cities, and another shows the list of areas in the selected city. You might start with some code that looks like this: +Misalnya, pertimbangkan sebuah komponen `ShippingForm` yang menampilkan dua dropdown: satu menampilkan daftar kota, dan lainnya menampilkan daftar area di kota yang dipilih. Anda mungkin akan memulai dengan kode yang terlihat seperti ini: ```js {3-16,20-35} function ShippingForm({ country }) { const [cities, setCities] = useState(null); - // This Effect fetches cities for a country + // Effect ini mengambil data kota untuk suatu negara useEffect(() => { let ignore = false; fetch(`/api/cities?country=${country}`) @@ -1121,7 +1120,7 @@ function ShippingForm({ country }) { const [city, setCity] = useState(null); const [areas, setAreas] = useState(null); - // This Effect fetches areas for the selected city + // Effect ini mengambil data area untuk kota yang dipilih useEffect(() => { if (city) { let ignore = false; @@ -1141,7 +1140,7 @@ function ShippingForm({ country }) { // ... ``` -Although this code is quite repetitive, [it's correct to keep these Effects separate from each other.](/learn/removing-effect-dependencies#is-your-effect-doing-several-unrelated-things) They synchronize two different things, so you shouldn't merge them into one Effect. Instead, you can simplify the `ShippingForm` component above by extracting the common logic between them into your own `useData` Hook: +Meskipun kode ini cukup berulang, [memisahkan Efek ini satu sama lain adalah benar.](/learn/removing-effect-dependencies#is-your-effect-doing-several-unrelated-things) Keduanya menyinkronkan dua hal yang berbeda, sehingga Anda tidak boleh menggabungkannya menjadi satu Efek. Sebagai gantinya, Anda dapat menyederhanakan komponen `ShippingForm` di atas dengan mengekstrak logika umum di antara mereka ke dalam `useData` Hook Anda sendiri: ```js {2-18} function useData(url) { @@ -1165,7 +1164,7 @@ function useData(url) { } ``` -Now you can replace both Effects in the `ShippingForm` components with calls to `useData`: +Sekarang Anda dapat mengganti kedua Efek di komponen `ShippingForm` dengan panggilan ke `useData`: ```js {2,4} function ShippingForm({ country }) { @@ -1175,39 +1174,39 @@ function ShippingForm({ country }) { // ... ``` -Extracting a custom Hook makes the data flow explicit. You feed the `url` in and you get the `data` out. By "hiding" your Effect inside `useData`, you also prevent someone working on the `ShippingForm` component from adding [unnecessary dependencies](/learn/removing-effect-dependencies) to it. With time, most of your app's Effects will be in custom Hooks. +Mengekstrak custom Hook membuat aliran data menjadi eksplisit. Anda memasukkan `url` dan Anda mengeluarkan `data`. Dengan "menyembunyikan" Efek Anda di dalam `useData`, Anda juga mencegah seseorang yang bekerja pada komponen `ShippingForm` menambahkan [dependensi yang tidak diperlukan](/learn/removing-effect-dependencies) ke dalamnya. Seiring waktu, sebagian besar Efek aplikasi Anda akan berada di dalam custom Hooks. -#### Keep your custom Hooks focused on concrete high-level use cases {/*keep-your-custom-hooks-focused-on-concrete-high-level-use-cases*/} +#### Tetap fokuskan custom Hooks Anda pada kasus penggunaan tingkat tinggi yang konkret {/*keep-your-custom-hooks-focused-on-concrete-high-level-use-cases*/} -Start by choosing your custom Hook's name. If you struggle to pick a clear name, it might mean that your Effect is too coupled to the rest of your component's logic, and is not yet ready to be extracted. +Mulailah dengan memilih nama untuk custom Hook Anda. Jika Anda kesulitan memilih nama yang jelas, itu mungkin berarti Effect Anda terlalu terkait dengan logika komponen Anda yang lain, dan belum siap untuk diekstrak. -Ideally, your custom Hook's name should be clear enough that even a person who doesn't write code often could have a good guess about what your custom Hook does, what it takes, and what it returns: +Idealnya, nama custom Hook Anda harus cukup jelas sehingga bahkan orang yang tidak sering menulis kode dapat memiliki tebakan yang baik tentang apa yang dilakukan oleh custom Hook Anda, apa yang diperlukan, dan apa yang dikembalikan: * ✅ `useData(url)` * ✅ `useImpressionLog(eventName, extraData)` * ✅ `useChatRoom(options)` -When you synchronize with an external system, your custom Hook name may be more technical and use jargon specific to that system. It's good as long as it would be clear to a person familiar with that system: +Ketika Anda melakukan sinkronisasi dengan sistem eksternal, nama custom Hook Anda mungkin lebih teknis dan menggunakan jargon yang spesifik untuk sistem itu. Itu bagus selama jelas bagi orang yang akrab dengan sistem tersebut: * ✅ `useMediaQuery(query)` * ✅ `useSocket(url)` * ✅ `useIntersectionObserver(ref, options)` -**Keep custom Hooks focused on concrete high-level use cases.** Avoid creating and using custom "lifecycle" Hooks that act as alternatives and convenience wrappers for the `useEffect` API itself: +**Tetap fokuskan custom Hooks pada kasus penggunaan tingkat tinggi yang konkret.** Hindari membuat dan menggunakan custom "lifecycle" Hooks yang bertindak sebagai pembungkus alternatif dan praktis untuk API `useEffect` itu sendiri: * 🔴 `useMount(fn)` * 🔴 `useEffectOnce(fn)` * 🔴 `useUpdateEffect(fn)` -For example, this `useMount` Hook tries to ensure some code only runs "on mount": +Sebagai contoh, Hook `useMount` ini mencoba memastikan beberapa kode hanya berjalan "pada mount": ```js {4-5,14-15} function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); - // 🔴 Avoid: using custom "lifecycle" Hooks + // 🔴 Hindari: menggunakan custom "lifecycle" Hooks useMount(() => { const connection = createConnection({ roomId, serverUrl }); connection.connect(); @@ -1217,23 +1216,23 @@ function ChatRoom({ roomId }) { // ... } -// 🔴 Avoid: creating custom "lifecycle" Hooks +// 🔴 Hindari: membuat custom "lifecycle" Hooks function useMount(fn) { useEffect(() => { fn(); - }, []); // 🔴 React Hook useEffect has a missing dependency: 'fn' + }, []); // 🔴 React Hook useEffect memiliki dependensi yang hilang: 'fn' } ``` -**Custom "lifecycle" Hooks like `useMount` don't fit well into the React paradigm.** For example, this code example has a mistake (it doesn't "react" to `roomId` or `serverUrl` changes), but the linter won't warn you about it because the linter only checks direct `useEffect` calls. It won't know about your Hook. +**Custom "lifecycle" Hook seperti `useMount` tidak cocok dengan paradigma React.** Sebagai contoh, contoh kode ini memiliki kesalahan (tidak "merespons" terhadap perubahan `roomId` atau `serverUrl`) , tetapi linter tidak akan memperingatkan Anda tentang hal itu karena linter hanya memeriksa panggilan `useEffect` langsung. Itu tidak akan tahu tentang Hook Anda. -If you're writing an Effect, start by using the React API directly: +Jika Anda menulis sebuah Effect, mulailah dengan menggunakan API React secara langsung: ```js function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); - // ✅ Good: two raw Effects separated by purpose + // ✅ Baik: dua raw Effects yang dipisahkan berdasarkan tujuan useEffect(() => { const connection = createConnection({ serverUrl, roomId }); @@ -1249,28 +1248,28 @@ function ChatRoom({ roomId }) { } ``` -Then, you can (but don't have to) extract custom Hooks for different high-level use cases: +Kemudian, Anda dapat (tetapi tidak harus) mengekstrak custom Hooks untuk kasus penggunaan tingkat tinggi yang berbeda: ```js function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); - // ✅ Great: custom Hooks named after their purpose + // ✅ Hebat: custom Hooks dengan nama sesuai tujuan useChatRoom({ serverUrl, roomId }); useImpressionLog('visit_chat', { roomId }); // ... } ``` -**A good custom Hook makes the calling code more declarative by constraining what it does.** For example, `useChatRoom(options)` can only connect to the chat room, while `useImpressionLog(eventName, extraData)` can only send an impression log to the analytics. If your custom Hook API doesn't constrain the use cases and is very abstract, in the long run it's likely to introduce more problems than it solves. +**Custom Hook yang baik membuat kode yang dipanggil lebih deklaratif dengan membatasi apa yang dilakukannya.** Sebagai contoh, `useChatRoom(options)` hanya dapat terhubung ke ruang obrolan, sementara `useImpressionLog(eventName, extraData)` hanya dapat mengirim log impresi ke analitik. Jika API custom Hook Anda tidak membatasi kasus penggunaan dan sangat abstrak, dalam jangka panjang kemungkinan akan menimbulkan lebih banyak masalah daripada penyelesaiannya. -### Custom Hooks help you migrate to better patterns {/*custom-hooks-help-you-migrate-to-better-patterns*/} +### Custom Hooks membantu Anda bermigrasi ke pola yang lebih baik {/*custom-hooks-help-you-migrate-to-better-patterns*/} -Effects are an ["escape hatch"](/learn/escape-hatches): you use them when you need to "step outside React" and when there is no better built-in solution for your use case. With time, the React team's goal is to reduce the number of the Effects in your app to the minimum by providing more specific solutions to more specific problems. Wrapping your Effects in custom Hooks makes it easier to upgrade your code when these solutions become available. +Effects merupakan sebuah ["escape hatch"](/learn/escape-hatches): Anda menggunakannya ketika Anda perlu "keluar dari React" dan ketika tidak ada solusi bawaan yang lebih baik untuk kasus penggunaan Anda. Seiring waktu, tujuan tim React adalah untuk mengurangi jumlah Effects di aplikasi Anda seminimal mungkin dengan memberikan solusi yang lebih spesifik untuk masalah yang lebih spesifik. Membungkus Effects Anda dalam custom Hooks memudahkan untuk memutakhirkan kode Anda ketika solusi-solusi ini tersedia. -Let's return to this example: +Mari kita kembali ke contoh ini: @@ -1331,9 +1330,9 @@ export function useOnlineStatus() { -In the above example, `useOnlineStatus` is implemented with a pair of [`useState`](/reference/react/useState) and [`useEffect`.](/reference/react/useEffect) However, this isn't the best possible solution. There is a number of edge cases it doesn't consider. For example, it assumes that when the component mounts, `isOnline` is already `true`, but this may be wrong if the network already went offline. You can use the browser [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) API to check for that, but using it directly would not work on the server for generating the initial HTML. In short, this code could be improved. +Dalam contoh di atas, `useOnlineStatus` diimplementasikan dengan sepasang [`useState`](/reference/react/useState) dan [`useEffect`.](/reference/react/useEffect) Namun, ini bukanlah solusi terbaik. Ada beberapa kasus tepi yang tidak dipertimbangkan. Misalnya, diasumsikan bahwa ketika komponen dipasang, `isOnline` sudah `benar`, tetapi hal ini mungkin salah jika jaringan sudah offline. Anda dapat menggunakan API browser [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) untuk memeriksanya, tetapi menggunakannya secara langsung tidak akan berhasil di server untuk menghasilkan HTML awal. Singkatnya, kode ini dapat diperbaiki. -Luckily, React 18 includes a dedicated API called [`useSyncExternalStore`](/reference/react/useSyncExternalStore) which takes care of all of these problems for you. Here is how your `useOnlineStatus` Hook, rewritten to take advantage of this new API: +Untungnya, React 18 menyertakan API khusus yang disebut [`useSyncExternalStore`](/reference/react/useSyncExternalStore) yang menangani semua masalah ini untuk Anda. Berikut adalah bagaimana Hook `useOnlineStatus` Anda, ditulis ulang untuk memanfaatkan API baru ini: @@ -1384,8 +1383,8 @@ function subscribe(callback) { export function useOnlineStatus() { return useSyncExternalStore( subscribe, - () => navigator.onLine, // How to get the value on the client - () => true // How to get the value on the server + () => navigator.onLine, // Bagaimana cara mendapatkan nilai di sisi klien + () => true // Bagaimana cara mendapatkan nilai di sisi server ); } @@ -1393,7 +1392,7 @@ export function useOnlineStatus() { -Notice how **you didn't need to change any of the components** to make this migration: +Perhatikan bagaimana **Anda tidak perlu mengubah komponen apa pun** untuk melakukan migrasi ini: ```js {2,7} function StatusBar() { @@ -1407,22 +1406,22 @@ function SaveButton() { } ``` -This is another reason for why wrapping Effects in custom Hooks is often beneficial: +Ini adalah alasan lain mengapa membungkus Effects di custom Hooks seringkali bermanfaat: -1. You make the data flow to and from your Effects very explicit. -2. You let your components focus on the intent rather than on the exact implementation of your Effects. -3. When React adds new features, you can remove those Effects without changing any of your components. +1. Anda membuat aliran data ke dan dari Effects Anda sangat eksplisit. +2. Anda membiarkan komponen Anda fokus pada maksud daripada pada implementasi yang tepat dari Effects Anda. +3. Saat React menambahkan fitur baru, Anda dapat menghapus Effects tersebut tanpa mengubah komponen apa pun. -Similar to a [design system,](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969) you might find it helpful to start extracting common idioms from your app's components into custom Hooks. This will keep your components' code focused on the intent, and let you avoid writing raw Effects very often. Many excellent custom Hooks are maintained by the React community. +Mirip dengan [sistem desain,](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969) Anda mungkin merasa terbantu untuk mulai mengekstraksi idiom umum dari komponen aplikasi Anda ke dalam custom Hooks. Ini akan membuat kode komponen Anda tetap fokus pada maksud, dan memungkinkan Anda menghindari menulis Effects mentah terlalu sering. Banyak custom Hooks yang sangat baik dikelola oleh komunitas React. -#### Will React provide any built-in solution for data fetching? {/*will-react-provide-any-built-in-solution-for-data-fetching*/} +#### Akankah React akan menyediakan solusi bawaan untuk pengambilan data? {/*will-react-provide-any-built-in-solution-for-data-fetching*/} -We're still working out the details, but we expect that in the future, you'll write data fetching like this: +Kami masih mengerjakan detailnya, tetapi kami berharap di masa mendatang, Anda akan menulis pengambilan data seperti ini: ```js {1,4,6} -import { use } from 'react'; // Not available yet! +import { use } from 'react'; // Belum tersedia! function ShippingForm({ country }) { const cities = use(fetch(`/api/cities?country=${country}`)); @@ -1431,13 +1430,13 @@ function ShippingForm({ country }) { // ... ``` -If you use custom Hooks like `useData` above in your app, it will require fewer changes to migrate to the eventually recommended approach than if you write raw Effects in every component manually. However, the old approach will still work fine, so if you feel happy writing raw Effects, you can continue to do that. +Jika Anda menggunakan custom Hooks seperti `useData` di atas dalam aplikasi Anda, itu akan memerlukan lebih sedikit perubahan untuk bermigrasi ke pendekatan yang direkomendasikan daripada jika Anda menulis Effects mentah di setiap komponen secara manual. Namun, pendekatan lama akan tetap berfungsi dengan baik, jadi jika Anda merasa senang menulis Effects mentah, Anda dapat terus melakukannya. -### There is more than one way to do it {/*there-is-more-than-one-way-to-do-it*/} +### Ada lebih dari satu cara untuk melakukannya {/*there-is-more-than-one-way-to-do-it*/} -Let's say you want to implement a fade-in animation *from scratch* using the browser [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) API. You might start with an Effect that sets up an animation loop. During each frame of the animation, you could change the opacity of the DOM node you [hold in a ref](/learn/manipulating-the-dom-with-refs) until it reaches `1`. Your code might start like this: +Katakanlah Anda ingin mengimplementasikan animasi fade-in *dari awal* menggunakan API browser [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). Anda mungkin memulainya dengan sebuah Effect yang menyiapkan lingkaran animasi. Selama setiap frame animasi, Anda dapat mengubah opacity node DOM yang [disimpan di ref](/learn/manipulating-the-dom-with-refs) hingga mencapai `1`. Kode Anda mungkin dimulai seperti ini: @@ -1459,7 +1458,7 @@ function Welcome() { const progress = Math.min(timePassed / duration, 1); onProgress(progress); if (progress < 1) { - // We still have more frames to paint + // Masih ada banyak frame yang perlu diwarnai frameId = requestAnimationFrame(onFrame); } } @@ -1520,7 +1519,7 @@ html, body { min-height: 300px; } -To make the component more readable, you might extract the logic into a `useFadeIn` custom Hook: +Untuk membuat komponen lebih mudah dibaca, Anda dapat mengekstrak logika ke dalam custom Hook `useFadeIn`: @@ -1569,7 +1568,7 @@ export function useFadeIn(ref, duration) { const progress = Math.min(timePassed / duration, 1); onProgress(progress); if (progress < 1) { - // We still have more frames to paint + // Masih ada banyak frame yang perlu diwarnai frameId = requestAnimationFrame(onFrame); } } @@ -1611,7 +1610,7 @@ html, body { min-height: 300px; } -You could keep the `useFadeIn` code as is, but you could also refactor it more. For example, you could extract the logic for setting up the animation loop out of `useFadeIn` into a custom `useAnimationLoop` Hook: +Anda dapat mempertahankan kode `useFadeIn` apa adanya, tetapi Anda juga dapat merestrukturisasi lebih lanjut. Misalnya, Anda dapat mengekstrak logika untuk menyiapkan loop animasi dari `useFadeIn` menjadi custom Hook `useAnimationLoop`: @@ -1715,7 +1714,7 @@ html, body { min-height: 300px; } -However, you didn't *have to* do that. As with regular functions, ultimately you decide where to draw the boundaries between different parts of your code. You could also take a very different approach. Instead of keeping the logic in the Effect, you could move most of the imperative logic inside a JavaScript [class:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) +Namun, Anda tidak *harus* melakukan itu. Seperti halnya fungsi biasa, pada akhirnya Anda yang memutuskan di mana harus menggambar batas antara berbagai bagian kode Anda. Anda juga bisa mengambil pendekatan yang sangat berbeda. Alih-alih mempertahankan logika dalam Effect, Anda dapat memindahkan sebagian besar logika imperatif ke dalam JavaScript [class:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) @@ -1782,7 +1781,7 @@ export class FadeInAnimation { if (progress === 1) { this.stop(); } else { - // We still have more frames to paint + // Masih ada banyak frame yang perlu diwarnai this.frameId = requestAnimationFrame(() => this.onFrame()); } } @@ -1813,9 +1812,9 @@ html, body { min-height: 300px; } -Effects let you connect React to external systems. The more coordination between Effects is needed (for example, to chain multiple animations), the more it makes sense to extract that logic out of Effects and Hooks *completely* like in the sandbox above. Then, the code you extracted *becomes* the "external system". This lets your Effects stay simple because they only need to send messages to the system you've moved outside React. +Effects memungkinkan Anda menghubungkan React dengan sistem eksternal. Semakin banyak koordinasi antara Effects yang dibutuhkan (misalnya, untuk menghubungkan beberapa animasi), semakin masuk akal untuk mengekstrak logika tersebut dari Effects dan Hooks *sepenuhnya* seperti yang ditunjukkan di sandbox di atas. Kemudian, kode yang Anda ekstrak *menjadi* "sistem eksternal". Ini memungkinkan Effects Anda tetap sederhana karena mereka hanya perlu mengirim pesan ke sistem yang telah Anda pindahkan ke luar React. -The examples above assume that the fade-in logic needs to be written in JavaScript. However, this particular fade-in animation is both simpler and much more efficient to implement with a plain [CSS Animation:](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) +Contoh di atas mengasumsikan bahwa logika fade-in perlu ditulis dalam JavaScript. Namun, animasi fade-in khusus ini lebih sederhana dan jauh lebih efisien untuk diterapkan dengan [Animasi CSS:](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) biasa @@ -1870,27 +1869,27 @@ html, body { min-height: 300px; } -Sometimes, you don't even need a Hook! +Terkadang, Anda bahkan tidak perlu menggunakan Hook! -- Custom Hooks let you share logic between components. -- Custom Hooks must be named starting with `use` followed by a capital letter. -- Custom Hooks only share stateful logic, not state itself. -- You can pass reactive values from one Hook to another, and they stay up-to-date. -- All Hooks re-run every time your component re-renders. -- The code of your custom Hooks should be pure, like your component's code. -- Wrap event handlers received by custom Hooks into Effect Events. -- Don't create custom Hooks like `useMount`. Keep their purpose specific. -- It's up to you how and where to choose the boundaries of your code. +- Custom Hook memungkinkan Anda untuk berbagi logika antar komponen. +- Custom Hook harus diberi nama yang dimulai dengan `use` diikuti oleh huruf kapital. +- Custom Hook hanya berbagi logika yang berhubungan dengan state, bukan state itu sendiri. +- Anda dapat meneruskan nilai reaktif dari satu Hook ke Hook lainnya, dan nilai tersebut tetap up-to-date. +- Semua Hook dijalankan ulang setiap kali komponen Anda di-*render* ulang. +- Kode dari custom Hook Anda harus bersifat murni, seperti kode komponen Anda. +- Bungkus event handler yang diterima oleh custom Hook menjadi Effect Events. +- Jangan membuat Custom Hook seperti `useMount`. Jaga agar tujuan mereka tetap spesifik. +- Itu terserah Anda bagaimana dan di mana Anda memilih batasan dalam kode Anda. -#### Extract a `useCounter` Hook {/*extract-a-usecounter-hook*/} +#### Ekstrak custom Hook `useCounter` {/*extract-a-usecounter-hook*/} -This component uses a state variable and an Effect to display a number that increments every second. Extract this logic into a custom Hook called `useCounter`. Your goal is to make the `Counter` component implementation look exactly like this: +Komponen ini menggunakan variabel state dan Effect untuk menampilkan angka yang bertambah setiap detik. Ekstrak logika ini menjadi custom Hook bernama `useCounter`. Tujuan Anda adalah membuat implementasi komponen `Counter` terlihat persis seperti ini: ```js export default function Counter() { @@ -1899,7 +1898,7 @@ export default function Counter() { } ``` -You'll need to write your custom Hook in `useCounter.js` and import it into the `Counter.js` file. +Anda perlu menulis custom Hook Anda di dalam file `useCounter.js` dan mengimpornya ke file `Counter.js`. @@ -1919,14 +1918,14 @@ export default function Counter() { ``` ```js useCounter.js -// Write your custom Hook in this file! +// Tulis custom Hook Anda di file ini! ``` -Your code should look like this: +Kode Anda harus terlihat seperti ini: @@ -1956,13 +1955,13 @@ export function useCounter() { -Notice that `App.js` doesn't need to import `useState` or `useEffect` anymore. +Perhatikan bahwa `App.js` tidak perlu mengimpor `useState` atau `useEffect` lagi. -#### Make the counter delay configurable {/*make-the-counter-delay-configurable*/} +#### Buat penundaan hitungan mundur dapat dikonfigurasi {/*make-the-counter-delay-configurable*/} -In this example, there is a `delay` state variable controlled by a slider, but its value is not used. Pass the `delay` value to your custom `useCounter` Hook, and change the `useCounter` Hook to use the passed `delay` instead of hardcoding `1000` ms. +Pada contoh ini, terdapat variabel status `delay` yang dikontrol oleh slider, tetapi nilainya tidak digunakan. Teruskan nilai `delay` ke dalam custom Hook `useCounter` Anda, dan ubah Hook `useCounter` untuk menggunakan `delay` yang diteruskan daripada `1000` ms yang telah di-hardcode. @@ -2012,7 +2011,7 @@ export function useCounter() { -Pass the `delay` to your Hook with `useCounter(delay)`. Then, inside the Hook, use `delay` instead of the hardcoded `1000` value. You'll need to add `delay` to your Effect's dependencies. This ensures that a change in `delay` will reset the interval. +Teruskan `delay` ke Hook Anda dengan `useCounter(delay)`. Kemudian, di dalam Hook, gunakan `delay` sebagai pengganti nilai `1000` yang telah di-hardcode. Anda perlu menambahkan `delay` ke dependencies Effect Anda. Hal ini memastikan bahwa perubahan pada `delay` akan mengatur ulang interval. @@ -2062,9 +2061,9 @@ export function useCounter(delay) { -#### Extract `useInterval` out of `useCounter` {/*extract-useinterval-out-of-usecounter*/} +#### Ekstrak `useInterval` dari `useCounter` {/*extract-useinterval-out-of-usecounter*/} -Currently, your `useCounter` Hook does two things. It sets up an interval, and it also increments a state variable on every interval tick. Split out the logic that sets up the interval into a separate Hook called `useInterval`. It should take two arguments: the `onTick` callback, and the `delay`. After this change, your `useCounter` implementation should look like this: +Saat ini, custom Hook `useCounter` Anda melakukan dua hal. Ia mengatur interval, dan juga menambah variabel state pada setiap kali interval berjalan. Pisahkan logika yang mengatur interval menjadi custom Hook terpisah yang disebut `useInterval`. Ia harus menerima dua argumen: callback `onTick`, dan `delay`. Setelah perubahan ini, implementasi `useCounter` Anda akan terlihat seperti ini: ```js export function useCounter(delay) { @@ -2076,7 +2075,7 @@ export function useCounter(delay) { } ``` -Write `useInterval` in the `useInterval.js` file and import it into the `useCounter.js` file. +Tulislah `useInterval` di dalam file `useInterval.js` dan impor ke dalam file `useCounter.js`. @@ -2106,14 +2105,14 @@ export function useCounter(delay) { ``` ```js useInterval.js -// Write your Hook here! +// Tulislah Hook Anda di sini! ``` -The logic inside `useInterval` should set up and clear the interval. It doesn't need to do anything else. +Logika di dalam `useInterval` harus mengatur dan menghapus interval. Ia tidak perlu melakukan hal lain. @@ -2152,17 +2151,17 @@ export function useInterval(onTick, delay) { -Note that there is a bit of a problem with this solution, which you'll solve in the next challenge. +Perhatikan bahwa ada sedikit masalah dengan solusi ini, yang akan Anda selesaikan pada tantangan berikutnya. -#### Fix a resetting interval {/*fix-a-resetting-interval*/} +#### Perbaiki interval yang direset {/*fix-a-resetting-interval*/} -In this example, there are *two* separate intervals. +Dalam contoh ini, ada *dua* interval terpisah. -The `App` component calls `useCounter`, which calls `useInterval` to update the counter every second. But the `App` component *also* calls `useInterval` to randomly update the page background color every two seconds. +Komponen `App` memanggil `useCounter`, yang kemudian memanggil `useInterval` untuk memperbarui hitungan setiap detik. Namun komponen `App` *juga* memanggil `useInterval` untuk memperbarui warna latar belakang halaman secara acak setiap dua detik. -For some reason, the callback that updates the page background never runs. Add some logs inside `useInterval`: +Untuk beberapa alasan, callback yang memperbarui warna latar belakang halaman tidak pernah berjalan. Tambahkan beberapa log di dalam `useInterval`: ```js {2,5} useEffect(() => { @@ -2175,13 +2174,13 @@ For some reason, the callback that updates the page background never runs. Add s }, [onTick, delay]); ``` -Do the logs match what you expect to happen? If some of your Effects seem to re-synchronize unnecessarily, can you guess which dependency is causing that to happen? Is there some way to [remove that dependency](/learn/removing-effect-dependencies) from your Effect? +Apakah log tersebut sesuai dengan yang Anda harapkan? Jika beberapa Effect Anda tampaknya melakukan sinkronisasi ulang secara tidak perlu, dapatkah Anda menebak dependensi mana yang menyebabkan hal tersebut terjadi? Apakah ada cara untuk [menghilangkan dependensi tersebut](/learn/removing-effect-dependencies) dari Effect Anda? -After you fix the issue, you should expect the page background to update every two seconds. +Setelah Anda memperbaiki masalah ini, Anda seharusnya melihat perubahan warna latar belakang halaman setiap dua detik. -It looks like your `useInterval` Hook accepts an event listener as an argument. Can you think of some way to wrap that event listener so that it doesn't need to be a dependency of your Effect? +Sepertinya custom Hook `useInterval` Anda menerima sebuah event listener sebagai argumen. Bisakah Anda memikirkan cara untuk membungkus event listener tersebut sehingga tidak perlu menjadi dependensi Effect Anda? @@ -2250,11 +2249,11 @@ export function useInterval(onTick, delay) { -Inside `useInterval`, wrap the tick callback into an Effect Event, as you did [earlier on this page.](/learn/reusing-logic-with-custom-hooks#passing-event-handlers-to-custom-hooks) +Di dalam `useInterval`, bungkus callback tick menjadi sebuah Event Effect, seperti yang Anda lakukan [sebelumnya di halaman ini.](/learn/reusing-logic-with-custom-hooks#passing-event-handlers-to-custom-hooks) -This will allow you to omit `onTick` from dependencies of your Effect. The Effect won't re-synchronize on every re-render of the component, so the page background color change interval won't get reset every second before it has a chance to fire. +Ini akan memungkinkan Anda menghilangkan `onTick` dari *dependensi* Effect Anda. Effect tidak akan disinkronkan setiap kali komponen di-*render* ulang, sehingga interval perubahan warna latar belakang halaman tidak akan diatur ulang setiap detik sebelum sempat aktif. -With this change, both intervals work as expected and don't interfere with each other: +Dengan perubahan ini, kedua interval akan berfungsi seperti yang diharapkan dan tidak saling mengganggu: @@ -2321,21 +2320,21 @@ export function useInterval(callback, delay) { -#### Implement a staggering movement {/*implement-a-staggering-movement*/} +#### Menerapkan gerakan bergiliran {/*implement-a-staggering-movement*/} -In this example, the `usePointerPosition()` Hook tracks the current pointer position. Try moving your cursor or your finger over the preview area and see the red dot follow your movement. Its position is saved in the `pos1` variable. +Dalam contoh ini, Hook `usePointerPosition()` melacak posisi pointer saat ini. Coba gerakkan kursor atau jari Anda ke area pratinjau dan lihat titik merah mengikuti gerakan Anda. Posisinya disimpan dalam variabel `pos1`. -In fact, there are five (!) different red dots being rendered. You don't see them because currently they all appear at the same position. This is what you need to fix. What you want to implement instead is a "staggered" movement: each dot should "follow" the previous dot's path. For example, if you quickly move your cursor, the first dot should follow it immediately, the second dot should follow the first dot with a small delay, the third dot should follow the second dot, and so on. +Faktanya, ada lima (!) titik merah yang berbeda yang di-*render*. Anda tidak melihat semuanya karena saat ini mereka semua muncul di posisi yang sama. Inilah yang perlu Anda perbaiki. Yang ingin Anda implementasikan adalah gerakan "bergiliran": setiap titik harus "mengikuti" jalur titik sebelumnya. Misalnya, jika Anda memindahkan kursor dengan cepat, titik pertama harus segera mengikuti dengan segera, titik kedua harus mengikuti titik pertama dengan penundaan kecil, titik ketiga harus mengikuti titik kedua, dan seterusnya. -You need to implement the `useDelayedValue` custom Hook. Its current implementation returns the `value` provided to it. Instead, you want to return the value back from `delay` milliseconds ago. You might need some state and an Effect to do this. +Anda perlu mengimplementasikan custom Hook `useDelayedValue`. Implementasi saat ini mengembalikan `value` yang diberikan kepadanya. Sebagai gantinya, Anda ingin mengembalikan nilai dari `delay` milidetik yang lalu. Anda mungkin memerlukan beberapa state dan sebuah Effect untuk melakukannya. -After you implement `useDelayedValue`, you should see the dots move following one another. +Setelah Anda mengimplementasikan `useDelayedValue`, Anda akan melihat titik-titik bergerak mengikuti satu sama lain. -You'll need to store the `delayedValue` as a state variable inside your custom Hook. When the `value` changes, you'll want to run an Effect. This Effect should update `delayedValue` after the `delay`. You might find it helpful to call `setTimeout`. +Anda harus menyimpan `delayedValue` sebagai variabel state di dalam custom Hook Anda. Saat `value` berubah, Anda ingin menjalankan sebuah Effect. Effect ini harus memperbarui `delayedValue` setelah `delay`. Anda mungkin merasa terbantu dengan memanggil `setTimeout`. -Does this Effect need cleanup? Why or why not? +Apakah Effect ini memerlukan pembersihan? Mengapa atau mengapa tidak? @@ -2345,7 +2344,7 @@ Does this Effect need cleanup? Why or why not? import { usePointerPosition } from './usePointerPosition.js'; function useDelayedValue(value, delay) { - // TODO: Implement this Hook + // TODO: Implementasi Hook ini return value; } @@ -2408,7 +2407,7 @@ body { min-height: 300px; } -Here is a working version. You keep the `delayedValue` as a state variable. When `value` updates, your Effect schedules a timeout to update the `delayedValue`. This is why the `delayedValue` always "lags behind" the actual `value`. +Berikut ini adalah versi yang berfungsi. Anda menyimpan `delayedValue` sebagai variabel state. Ketika `value` diperbarui, Effect Anda menjadwalkan timeout untuk memperbarui `delayedValue`. Inilah mengapa `delayedValue` selalu "terlambat" dibandingkan `value` yang sebenarnya. @@ -2485,7 +2484,7 @@ body { min-height: 300px; } -Note that this Effect *does not* need cleanup. If you called `clearTimeout` in the cleanup function, then each time the `value` changes, it would reset the already scheduled timeout. To keep the movement continuous, you want all the timeouts to fire. +Perhatikan bahwa Effect ini *tidak* memerlukan pembersihan. Jika Anda memanggil `clearTimeout` dalam fungsi pembersihan, maka setiap kali `value` berubah, timeout yang sudah dijadwalkan akan diatur ulang. Agar gerakan terus berlanjut, Anda ingin semua timeout tersebut berjalan. From 5bc25d3c36b6e67cd2d86a1145daf6dfa21d4f40 Mon Sep 17 00:00:00 2001 From: Kathryn Middleton Date: Thu, 18 May 2023 12:48:40 -0400 Subject: [PATCH 010/751] Add accessibility note to interactivity section in the new React docs (#6026) * Add accessibility note to interactivity section in the new React docs * Add a11y note to Responding to Events section * Update responding-to-events.md --------- Co-authored-by: dan --- src/content/learn/responding-to-events.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md index 782b6c0f14..4450c46130 100644 --- a/src/content/learn/responding-to-events.md +++ b/src/content/learn/responding-to-events.md @@ -313,6 +313,12 @@ button { margin-right: 10px; } Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later. + + + +Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [`
    - - - - React - + + + React
    diff --git a/src/components/MDX/BlogCard.tsx b/src/components/MDX/BlogCard.tsx index 9d86f9211e..ba610b1118 100644 --- a/src/components/MDX/BlogCard.tsx +++ b/src/components/MDX/BlogCard.tsx @@ -16,62 +16,62 @@ export interface BlogCardProps { function BlogCard({title, badge, date, icon, url, children}: BlogCardProps) { return ( - - -
    -
    -

    - {title} -

    -
    -
    -
    - {icon === 'labs' && ( - - - - )} - {icon === 'blog' && ( - - - - )} - {date} - {badge ? ( -
    - New -
    - ) : null} -
    - - {children} - - {children != null && ( -
    - Read more -
    + +
    ); } diff --git a/src/components/MDX/Link.tsx b/src/components/MDX/Link.tsx index 8986d07a5c..7bf041e565 100644 --- a/src/components/MDX/Link.tsx +++ b/src/components/MDX/Link.tsx @@ -13,7 +13,7 @@ function Link({ className, children, ...props -}: JSX.IntrinsicElements['a']) { +}: React.AnchorHTMLAttributes) { const classes = 'inline text-link dark:text-link-dark border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal'; const modifiedChildren = Children.toArray(children).map((child: any) => { @@ -41,11 +41,8 @@ function Link({ {modifiedChildren} ) : ( - - {/* eslint-disable-next-line jsx-a11y/anchor-has-content */} - - {modifiedChildren} - + + {modifiedChildren} )} diff --git a/src/components/MDX/Sandpack/DownloadButton.tsx b/src/components/MDX/Sandpack/DownloadButton.tsx index 4181dbe950..4d206fff83 100644 --- a/src/components/MDX/Sandpack/DownloadButton.tsx +++ b/src/components/MDX/Sandpack/DownloadButton.tsx @@ -7,19 +7,22 @@ import {useSandpack} from '@codesandbox/sandpack-react'; import {IconDownload} from '../../Icon/IconDownload'; export interface DownloadButtonProps {} -let supportsImportMap: boolean | void; +let supportsImportMap = false; + +function subscribe(cb: () => void) { + // This shouldn't actually need to update, but this works around + // https://github.com/facebook/react/issues/26095 + let timeout = setTimeout(() => { + supportsImportMap = + (HTMLScriptElement as any).supports && + (HTMLScriptElement as any).supports('importmap'); + cb(); + }, 0); + return () => clearTimeout(timeout); +} function useSupportsImportMap() { - function subscribe() { - // It never updates. - return () => {}; - } function getCurrentValue() { - if (supportsImportMap === undefined) { - supportsImportMap = - (HTMLScriptElement as any).supports && - (HTMLScriptElement as any).supports('importmap'); - } return supportsImportMap; } function getServerSnapshot() { diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 0e8f84f0dc..2a9743ec39 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -22,11 +22,7 @@ export interface SearchProps { } function Hit({hit, children}: any) { - return ( - - {children} - - ); + return {children}; } // Copy-pasted from @docsearch/react to avoid importing the whole bundle. diff --git a/yarn.lock b/yarn.lock index 5aa76ffbef..d6e0c82c16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -896,10 +896,10 @@ unist-util-visit "^4.0.0" vfile "^5.0.0" -"@next/env@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.2-canary.7.tgz#98cf3ed5e7d6af93965c708799ac02cb46ca3831" - integrity sha512-uk5yDvh8ra8PlIczZBTZKyt5Rf6a6mH2tGB3hwRAXD5hVLd74LzBQza2aYMEcDlRafAknsbL0dnqI3CkFYat9w== +"@next/env@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.1.tgz#57322da2630b6bb6d7204577b0a18f6f9324db0c" + integrity sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg== "@next/eslint-plugin-next@12.0.3": version "12.0.3" @@ -908,70 +908,50 @@ dependencies: glob "7.1.7" -"@next/swc-android-arm-eabi@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.2-canary.7.tgz#21811767685d8a58756bbfff23a4e61c8da65a15" - integrity sha512-pusM/ylasGBweiwhINtqWCgy5bOjLmIctFD0etpmh9+DqCg09yu58hJ1Dn/UTW8EbB1nkTP1z3dEoMKLh4fV2A== - -"@next/swc-android-arm64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.2-canary.7.tgz#278e709c31ac5aceebd5e7f66efb81dae40ccab6" - integrity sha512-x11T0ocPE9xrnqMeDzUMepN3P8CHIN8iiLgiFkbTbKTbSciuH3juOvKggJO9APZRG5Ch5eePWcCy2gHedAbhnA== - -"@next/swc-darwin-arm64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2-canary.7.tgz#7858ecf88a4e252ef6b66c59e38449a79647e362" - integrity sha512-tcO9hDaMfcbiaZp1B+HZcLzGGs36dnmjQ0YXyn6C88HEUoKyxanYleVHtTmWHlgsxxjZdDd/RzOze1ycWs2oXw== - -"@next/swc-darwin-x64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2-canary.7.tgz#9225324b6de548ce7fd21c31d4725910c5b7d136" - integrity sha512-WjAyU67zj69nRM2GNAnBLvghq4EHTyDzMO02GjG6yexVhDvkE0OFlvh0BQLI3DIOz+B3RjJRcW3OoHi8XzW9UA== - -"@next/swc-freebsd-x64@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.2-canary.7.tgz#cf3374f2c3ddf370ed27cac84258760b282b6981" - integrity sha512-cQrdPCMhP1Mc+pIt16FlC5BVgcXzLXRlm7qZ7wBRKG6r/IIIn/qNRFgQQcB3iyvfNZo7lURLKcfsxNmMGclldQ== - -"@next/swc-linux-arm-gnueabihf@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.2-canary.7.tgz#b8e82ec743ceadfce25b7e74dfb447913b603c44" - integrity sha512-LEL+dUe10FhQHyXq9Mul5pOJwKDtrAylh9chktWf8eFr14j/YrfPbkLHv1+tCK8brDV3afVJMl0IpoCo75Yfyg== - -"@next/swc-linux-arm64-gnu@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2-canary.7.tgz#1711f46f004553f3c8ab7546b49e65f88abbbfd6" - integrity sha512-mbDqHk3C76UGIzkOv+G5NslKiSYIXyWQwbkuty0+0wLVJttWjWi2dMN7DFJQPMNvBefU9/vxVJdUnGVGEZfUXw== - -"@next/swc-linux-arm64-musl@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2-canary.7.tgz#e20b71ce215280bc2cadcf94f9755fdf3ffc0b24" - integrity sha512-gJ3VQHuqb3ABiOKPxfWAJQdO4mp3yNnWIAPN8n52F7Zu38udbHXvcbIylWfQW/Qah+RRf7P7y2txH2kC07QOPA== - -"@next/swc-linux-x64-gnu@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2-canary.7.tgz#176cf50080f121537877dbdfb7d667be19333a8c" - integrity sha512-/PBLiC+JfMJIzwMCQaSQgnLoIOjdSjTA9zarj2Kk1eCLjH8/VnsfBWtmP7TdbgIRYnZ8QKb4HXSOq94ZQS/fkw== - -"@next/swc-linux-x64-musl@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2-canary.7.tgz#96b858043d76b87f90b7da43afe13c5942dbceea" - integrity sha512-Bf3goHoUd0SB58sVTMva0ByoLM+aEhm5YJRqsi7SsOAu9EAQwYfWgY2Hx60ah5i1N4ihYK0xjs8kwlfdDVOuow== - -"@next/swc-win32-arm64-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2-canary.7.tgz#dd1a36d4afbecc623e71426897cea683a3a75666" - integrity sha512-aPRQ4dY5MuLgHCVdY+/Grgg4oX38pG4S0sT8mpatK3oIdjhj3961cj33QpPAy6dhhCs8m0/eCWYmM9KKlAAUsg== - -"@next/swc-win32-ia32-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2-canary.7.tgz#a7455ea57f88345a92c0067e82aa1b7aa5728088" - integrity sha512-hr+TBDICVezyn0HDK4QootalbcuLj9F8qUzZZAw3gHz16rUDpqpnlRjw3RC99AzkKL7qMsdR/+SwnBlBY7ZK7Q== - -"@next/swc-win32-x64-msvc@12.3.2-canary.7": - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2-canary.7.tgz#4e0d6d567c254e2cf00738f876ddafe5b611ee03" - integrity sha512-1n29b6meb54h/Mw/1xPoJB682nWbtEsUQo7rFJ6G44Nj3fYFXe+XOWQxWu6Sl8yvdBXcZRhRCHuAZGqYtmqorQ== +"@next/swc-darwin-arm64@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz#3748040d2dd0d89d3cdcc897f96aeda5130eed8f" + integrity sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg== + +"@next/swc-darwin-x64@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz#c59fc270005f17e04eb7eab4fd68793d0e3409a4" + integrity sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw== + +"@next/swc-linux-arm64-gnu@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz#1aef371bcef5d832d7f7e3aec3e68cfb98282393" + integrity sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg== + +"@next/swc-linux-arm64-musl@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz#2522927cb0af6918405a49f5a1d1687d6847f3ec" + integrity sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA== + +"@next/swc-linux-x64-gnu@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz#5ec9418a35510048a5ceb79ed300463e1a9b312d" + integrity sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA== + +"@next/swc-linux-x64-musl@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz#3478b9c89b75c1d0e7def9f35a9a77cb15d1a115" + integrity sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A== + +"@next/swc-win32-arm64-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz#efe53d48ff51d2485eabb910ab7caee78425fc01" + integrity sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA== + +"@next/swc-win32-ia32-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz#952cdf1c53df46a90d5151d99310195d2c384e55" + integrity sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g== + +"@next/swc-win32-x64-msvc@13.4.1": + version "13.4.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz#447b7dcee5f5d4824cdff331a4ec34b13d0b449d" + integrity sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1022,10 +1002,10 @@ resolved "https://registry.yarnpkg.com/@stitches/core/-/core-1.2.8.tgz#dce3b8fdc764fbc6dbea30c83b73bfb52cf96173" integrity sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg== -"@swc/helpers@0.4.11": - version "0.4.11" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de" - integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw== +"@swc/helpers@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" + integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg== dependencies: tslib "^2.4.0" @@ -1684,6 +1664,13 @@ browserslist@^4.20.2: node-releases "^2.0.6" update-browserslist-db "^1.0.5" +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1852,6 +1839,11 @@ cli-truncate@^3.1.0: slice-ansi "^5.0.0" string-width "^5.0.0" +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + codesandbox-import-util-types@^1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-1.3.7.tgz#7a6097e248a75424d13b06b74368cd76bd2b3e10" @@ -4488,31 +4480,28 @@ next-tick@^1.1.0: resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -next@12.3.2-canary.7: - version "12.3.2-canary.7" - resolved "https://registry.yarnpkg.com/next/-/next-12.3.2-canary.7.tgz#c739348174a3d7d97a638aa409376a96577a31d8" - integrity sha512-zUosveWzpeRVy7j4ANoJ4gu0TBrkLYwPlIUEXrqqs/zLpHMu+tanxA1R1ts2d7h/2dSmeVZgGcHiVcHj5uspEA== +next@^13.4.1: + version "13.4.1" + resolved "https://registry.yarnpkg.com/next/-/next-13.4.1.tgz#8d23f94c81b3f9cc8b34165ad528457e5befd726" + integrity sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA== dependencies: - "@next/env" "12.3.2-canary.7" - "@swc/helpers" "0.4.11" + "@next/env" "13.4.1" + "@swc/helpers" "0.5.1" + busboy "1.6.0" caniuse-lite "^1.0.30001406" postcss "8.4.14" - styled-jsx "5.0.7" - use-sync-external-store "1.2.0" + styled-jsx "5.1.1" + zod "3.21.4" optionalDependencies: - "@next/swc-android-arm-eabi" "12.3.2-canary.7" - "@next/swc-android-arm64" "12.3.2-canary.7" - "@next/swc-darwin-arm64" "12.3.2-canary.7" - "@next/swc-darwin-x64" "12.3.2-canary.7" - "@next/swc-freebsd-x64" "12.3.2-canary.7" - "@next/swc-linux-arm-gnueabihf" "12.3.2-canary.7" - "@next/swc-linux-arm64-gnu" "12.3.2-canary.7" - "@next/swc-linux-arm64-musl" "12.3.2-canary.7" - "@next/swc-linux-x64-gnu" "12.3.2-canary.7" - "@next/swc-linux-x64-musl" "12.3.2-canary.7" - "@next/swc-win32-arm64-msvc" "12.3.2-canary.7" - "@next/swc-win32-ia32-msvc" "12.3.2-canary.7" - "@next/swc-win32-x64-msvc" "12.3.2-canary.7" + "@next/swc-darwin-arm64" "13.4.1" + "@next/swc-darwin-x64" "13.4.1" + "@next/swc-linux-arm64-gnu" "13.4.1" + "@next/swc-linux-arm64-musl" "13.4.1" + "@next/swc-linux-x64-gnu" "13.4.1" + "@next/swc-linux-x64-musl" "13.4.1" + "@next/swc-win32-arm64-msvc" "13.4.1" + "@next/swc-win32-ia32-msvc" "13.4.1" + "@next/swc-win32-x64-msvc" "13.4.1" nice-try@^1.0.4: version "1.0.5" @@ -5357,13 +5346,13 @@ react-devtools-inline@4.4.0: dependencies: es6-symbol "^3" -react-dom@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-cb5084d1c-20220924.tgz#7a8334c5cf4baeb5651ca76fc9eb92ebbaf223bf" - integrity sha512-0IHzPGHESn3uu8nI1w5596GX8bCGCE94DpaHkKSGWOlB6uhoVecU0fyOCkkNuB4cMc9WeOWiH2gsM100EWZDPQ== +react-dom@^0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-16d053d59-20230506.tgz#1870c355f1027262992b2226191810ba15eedab3" + integrity sha512-I4PIT9ZAdDgpbav9BxfzPv2p5otJz6BEbFEBvFwd1BnQJmtkKKApUU7RYdGKnwY2/r6hdfxPm2pne+NhiyBkzg== dependencies: loose-envify "^1.1.0" - scheduler "0.0.0-experimental-cb5084d1c-20220924" + scheduler "0.0.0-experimental-16d053d59-20230506" react-is@^16.13.1: version "16.13.1" @@ -5375,10 +5364,10 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-cb5084d1c-20220924.tgz#ab661af674be824ae2989467506443b8bc4318d3" - integrity sha512-66AdfxkJrwCaCEKT0LQRd9J9GQ9T+yN7Wx9XT+tNxKycYQ0Exm+DZxOTedagWDlsFMXroyhrTWzgdC18R2PaOQ== +react@^0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-16d053d59-20230506.tgz#98a7a9d19ab1820f882111ce4fc4e23f3cb8aaad" + integrity sha512-8PdloFcanNcryJLohpr4rVQfB4oJvsL0Z+TzJ8B66RxauwF95QqUNorGsK1heESrtj4As0oHCmiZkoYzA4uW8w== dependencies: loose-envify "^1.1.0" @@ -5709,10 +5698,10 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scheduler@0.0.0-experimental-cb5084d1c-20220924: - version "0.0.0-experimental-cb5084d1c-20220924" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-cb5084d1c-20220924.tgz#9986680e1fbf7e4ccfe7606fef5920939d3a1abe" - integrity sha512-SeszKCdhM5OHxNMStjpKIAaloARUMZqIpDZjkZeGuRsyr7YlAqvlsCXyee4ZQOOU1pbr7BIvQntKy5Hil+DQJA== +scheduler@0.0.0-experimental-16d053d59-20230506: + version "0.0.0-experimental-16d053d59-20230506" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-16d053d59-20230506.tgz#cb76957af2849452a5e40c82fb53168da255e32f" + integrity sha512-gGnyU4CkC/+msd1dOQW9zuquI3GoEziuS42soP0AvbTCvRkeU4qhR/mRRaU+/a7JK/OFeSSudcz7enkrkZdSPA== dependencies: loose-envify "^1.1.0" @@ -5941,6 +5930,11 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -6066,10 +6060,12 @@ style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" -styled-jsx@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48" - integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA== +styled-jsx@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" + integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== + dependencies: + client-only "0.0.1" supports-color@^5.3.0: version "5.5.0" @@ -6494,11 +6490,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -use-sync-external-store@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== - util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -6684,6 +6675,11 @@ yaml@^1.10.0, yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +zod@3.21.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" + integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== + zwitch@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1" From 922c211dd7c3f5ab2c422cef4604dc78557c25bd Mon Sep 17 00:00:00 2001 From: Rhenald Karrel <65062403+rhenaldkarrel@users.noreply.github.com> Date: Sat, 20 May 2023 17:09:03 +0700 Subject: [PATCH 013/751] docs: translate PureComponent page (#562) --- src/content/reference/react/PureComponent.md | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/content/reference/react/PureComponent.md b/src/content/reference/react/PureComponent.md index 3e2d074e10..b7ea7da25f 100644 --- a/src/content/reference/react/PureComponent.md +++ b/src/content/reference/react/PureComponent.md @@ -4,13 +4,13 @@ title: PureComponent -We recommend defining components as functions instead of classes. [See how to migrate.](#alternatives) +Kami menyarankan untuk membuat komponen sebagai fungsi, bukan kelas. [Lihat cara migrasinya.](#alternatives) -`PureComponent` is similar to [`Component`](/reference/react/Component) but it skips re-renders for same props and state. Class components are still supported by React, but we don't recommend using them in new code. +`PureComponent` mirip dengan [`Component`](/reference/react/Component) tetapi melewatkan proses *render* ulang untuk props dan state yang sama. Komponen kelas masih didukung oleh React, tetapi kami tidak menyarankan untuk menggunakannya dalam kode baru. ```js class Greeting extends PureComponent { @@ -26,11 +26,11 @@ class Greeting extends PureComponent { --- -## Reference {/*reference*/} +## Referensi {/*reference*/} ### `PureComponent` {/*purecomponent*/} -To skip re-rendering a class component for same props and state, extend `PureComponent` instead of [`Component`:](/reference/react/Component) +Untuk melewatkan *render* ulang sebuah komponen kelas untuk props dan state yang sama, perluas `PureComponent`, bukan [`Component`:](/reference/react/Component) ```js import { PureComponent } from 'react'; @@ -42,18 +42,18 @@ class Greeting extends PureComponent { } ``` -`PureComponent` is a subclass of `Component` and supports [all the `Component` APIs.](/reference/react/Component#reference) Extending `PureComponent` is equivalent to defining a custom [`shouldComponentUpdate`](/reference/react/Component#shouldcomponentupdate) method that shallowly compares props and state. +`PureComponent` adalah subkelas dari `Component` dan mendukung [semua API `Component`.](/reference/react/Component#reference) Memperluas `PureComponent` sama dengan mendefinisikan sebuah metode kustom [`shouldComponentUpdate`](/reference/react/Component#shouldcomponentupdate) yang membandingkan props dan state secara dangkal. -[See more examples below.](#usage) +[Lihat contoh lainnya di bawah ini.](#usage) --- -## Usage {/*usage*/} +## Penggunaan {/*usage*/} -### Skipping unnecessary re-renders for class components {/*skipping-unnecessary-re-renders-for-class-components*/} +### Melewatkan *render* ulang yang tidak perlu untuk komponen kelas {/*skipping-unnecessary-re-renders-for-class-components*/} -React normally re-renders a component whenever its parent re-renders. As an optimization, you can create a component that React will not re-render when its parent re-renders so long as its new props and state are the same as the old props and state. [Class components](/reference/react/Component) can opt into this behavior by extending `PureComponent`: +React umumnya me-*render* ulang sebuah komponen setiap kali induknya me-*render* ulang. Untuk mengoptimalkannya, Anda dapat membuat komponen yang tidak akan di-*render* ulang oleh React ketika induknya di-*render* ulang selama props dan state yang baru sama dengan props dan state yang lama. [Komponen kelas](/reference/react/Component) dapat memilih perilaku ini dengan memperluas `PureComponent`: ```js {1} class Greeting extends PureComponent { @@ -63,9 +63,9 @@ class Greeting extends PureComponent { } ``` -A React component should always have [pure rendering logic.](/learn/keeping-components-pure) This means that it must return the same output if its props, state, and context haven't changed. By using `PureComponent`, you are telling React that your component complies with this requirement, so React doesn't need to re-render as long as its props and state haven't changed. However, your component will still re-render if a context that it's using changes. +Sebuah komponen React harus selalu memiliki [logika me-*render* murni.](/learn/keeping-components-pure) Ini berarti komponen tersebut harus mengembalikan output yang sama jika props, state, dan konteksnya tidak berubah. Dengan menggunakan `PureComponent`, Anda memberi tahu React bahwa komponen Anda memenuhi persyaratan ini, sehingga React tidak perlu me-*render* ulang selama props dan state-nya belum berubah. Namun, komponen Anda akan tetap di-*render* ulang jika konteks yang digunakan berubah. -In this example, notice that the `Greeting` component re-renders whenever `name` is changed (because that's one of its props), but not when `address` is changed (because it's not passed to `Greeting` as a prop): +Pada contoh ini, perhatikan bahwa komponen `Greeting` di-*render* ulang setiap kali `name` diubah (karena itu adalah salah satu props-nya), tetapi tidak ketika `address` diubah (karena tidak dioper ke `Greeting` sebagai props): @@ -109,17 +109,17 @@ label { -We recommend defining components as functions instead of classes. [See how to migrate.](#alternatives) +Kami menyarankan untuk membuat komponen sebagai fungsi, bukan kelas. [Lihat cara migrasinya.](#alternatives) --- -## Alternatives {/*alternatives*/} +## Alternatif {/*alternatives*/} -### Migrating from a `PureComponent` class component to a function {/*migrating-from-a-purecomponent-class-component-to-a-function*/} +### Migrasi dari komponen kelas `PureComponent` ke sebuah fungsi {/*migrating-from-a-purecomponent-class-component-to-a-function*/} -We recommend using function components instead of [class components](/reference/react/Component) in new code. If you have some existing class components using `PureComponent`, here is how you can convert them. This is the original code: +Kami menyarankan untuk menggunakan komponen fungsi daripada [komponen kelas](/reference/react/Component) dalam kode baru. Jika Anda memiliki beberapa komponen kelas yang sudah ada menggunakan `PureComponent`, berikut ini cara mengonversinya. Ini adalah kode aslinya: @@ -161,7 +161,7 @@ label { -When you [convert this component from a class to a function,](/reference/react/Component#alternatives) wrap it in [`memo`:](/reference/react/memo) +Saat Anda [mengonversi komponen ini dari kelas ke fungsi,](/reference/react/Component#alternatives) bungkus komponen ini dengan [`memo`](/reference/react/memo): @@ -203,6 +203,6 @@ label { -Unlike `PureComponent`, [`memo`](/reference/react/memo) does not compare the new and the old state. In function components, calling the [`set` function](/reference/react/useState#setstate) with the same state [already prevents re-renders by default,](/reference/react/memo#updating-a-memoized-component-using-state) even without `memo`. +Tidak seperti `PureComponent`, [`memo`](/reference/react/memo) tidak membandingkan state yang baru dan state yang lama. Pada komponen fungsi, memanggil [fungsi `set`](/reference/react/useState#setstate) dengan state yang sama [sudah mencegah *render* ulang secara default,](/reference/react/memo#updating-a-memoized-component-using-state) bahkan tanpa `memo`. From f52e43027f419afd335ad531737322a6941046d5 Mon Sep 17 00:00:00 2001 From: Abraham Anak Agung Date: Sat, 20 May 2023 17:27:47 +0700 Subject: [PATCH 014/751] Translate Add React To an Existing Project to Bahasa (#495) --- .../learn/add-react-to-an-existing-project.md | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index 03f4912114..851f4916cc 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -1,59 +1,59 @@ --- -title: Add React to an Existing Project +title: Tambahkan React ke Proyek yang sudah Ada --- -If you want to add some interactivity to your existing project, you don't have to rewrite it in React. Add React to your existing stack, and render interactive React components anywhere. +Jika Anda ingin menambahkan beberapa interaktivitas ke proyek Anda yang sudah ada, Anda tidak perlu menulis ulang menggunakan React. Tambahkan React ke proyek Anda, dan Anda dapat me-*render* komponen interaktif React di mana saja. -**You need to install [Node.js](https://nodejs.org/en/) for local development.** Although you can [try React](/learn/installation#try-react) online or with a simple HTML page, realistically most JavaScript tooling you'll want to use for development requires Node.js. +**Anda perlu mengunduh [Node.js](https://nodejs.org/en/) untuk menjalankan lokal (*development*).** Meskipun Anda dapat mencoba [React](/learn/installation#try-react) secara online atau dengan halaman HTML sederhana, secara realistis sebagian besar tooling JavaScript yang ingin Anda gunakan untuk pengembangan memerlukan Node.js -## Using React for an entire subroute of your existing website {/*using-react-for-an-entire-subroute-of-your-existing-website*/} +## Menggunakan React untuk seluruh subroute dari situs web Anda yang sudah ada {/*using-react-for-an-entire-subroute-of-your-existing-website*/} -Let's say you have an existing web app at `example.com` built with another server technology (like Rails), and you want to implement all routes starting with `example.com/some-app/` fully with React. +Katakanlah Anda memiliki aplikasi web yang sudah ada di `example.com` yang dibuat dengan teknologi server lain (seperti Rails), dan Anda ingin mengimplementasikan semua rute yang dimulai dengan `example.com/some-app/` sepenuhnya dengan React. -Here's how we recommend to set it up: +Inilah cara kami menyarankan untuk menyiapkannya: -1. **Build the React part of your app** using one of the [React-based frameworks](/learn/start-a-new-react-project). -2. **Specify `/some-app` as the *base path*** in your framework's configuration (here's how: [Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)). -3. **Configure your server or a proxy** so that all requests under `/some-app/` are handled by your React app. +1. **Buat bagian React dari aplikasi Anda** menggunakan salah satu [*framework* berbasis React](/learn/start-a-new-react-project). +2. **Tentukan `/some-app` sebagai *base path*** dalam konfigurasi *framework* Anda (begini caranya: [Next.js](https://nextjs.org/docs/api-reference/next.config.js/basepath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)). +3. **Konfigurasi server Anda atau Proxy** sehingga semua permintaan di rute `/some-app/` ditangani oleh aplikasi React Anda. -This ensures the React part of your app can [benefit from the best practices](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) baked into those frameworks. +Ini memastikan bagian React dari aplikasi Anda bisa mendapatkan [keuntungan dari praktik terbaik](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) yang dimasukkan ke dalam *framework* tersebut. -Many React-based frameworks are full-stack and let your React app take advantage of the server. However, you can use the same approach even if you can't or don't want to run JavaScript on the server. In that case, serve the HTML/CSS/JS export ([`next export` output](https://nextjs.org/docs/advanced-features/static-html-export) for Next.js, default for Gatsby) at `/some-app/` instead. +Banyak *framework* berbasis React bersifat *full-stack* dan membiarkan aplikasi React Anda memanfaatkan server. Namun, Anda dapat menggunakan pendekatan yang sama meskipun Anda tidak dapat atau tidak ingin menjalankan JavaScript di server. Dalam hal ini, sajikan HTML/CSS/JS ([`next export` output](https://nextjs.org/docs/advanced-features/static-html-export) untuk Next.js, *default* untuk Gatsby) di `/some-app/` sebagai gantinya. -## Using React for a part of your existing page {/*using-react-for-a-part-of-your-existing-page*/} +## Menggunakan React sebagai bagian dari halaman Anda yang sudah ada {/*using-react-for-a-part-of-your-existing-page*/} -Let's say you have an existing page built with another technology (either a server one like Rails, or a client one like Backbone), and you want to render interactive React components somewhere on that page. That's a common way to integrate React--in fact, it's how most React usage looked at Meta for many years! +Katakanlah Anda memiliki halaman yang dibangun dengan teknologi lain (baik *server-based* seperti Rails, atau *client-based* seperti Backbone), dan Anda ingin me-*render* komponen interaktif React di suatu tempat di halaman itu. Itu adalah cara umum untuk mengintegrasikan React sebenarnya, begitulah cara sebagian besar penggunaan React di Meta selama bertahun-tahun! -You can do this in two steps: +Anda dapat melakukannya dengan dua cara: -1. **Set up a JavaScript environment** that lets you use the [JSX syntax](/learn/writing-markup-with-jsx), split your code into modules with the [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) / [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) syntax, and use packages (for example, React) from the [npm](https://www.npmjs.com/) package registry. -2. **Render your React components** where you want to see them on the page. +1. **Siapkan JavaScript *environment* Anda** yang memungkinkan Anda menggunakan [sintaks JSX](/learn/writing-markup-with-jsx), bagi kode Anda menjadi modul dengan sintaks [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) / [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export), dan gunakan paket (misalnya React) dari registri paket [npm](https://www.npmjs.com/). +2. **Tampilkan komponen React Anda** di tempat yang ingin Anda lihat di halaman. -The exact approach depends on your existing page setup, so let's walk through some details. +Pendekatan yang tepat tergantung pada setup halaman Anda, jadi mari kita telusuri beberapa detail. -### Step 1: Set up a modular JavaScript environment {/*step-1-set-up-a-modular-javascript-environment*/} +### Langkah 1: Siapkan lingkungan JavaScript modular {/*step-1-set-up-a-modular-javascript-environment*/} -A modular JavaScript environment lets you write your React components in individual files, as opposed to writing all of your code in a single file. It also lets you use all the wonderful packages published by other developers on the [npm](https://www.npmjs.com/) registry--including React itself! How you do this depends on your existing setup: +Lingkungan JavaScript modular memungkinkan Anda menulis komponen React Anda dalam file individual, bukan menulis semua kode Anda dalam satu file. Ini juga memungkinkan Anda menggunakan semua paket luar biasa yang diterbitkan oleh pengembang lain di registri [npm](https://www.npmjs.com/)--termasuk React itu sendiri! Cara Anda melakukannya tergantung pada pengaturan yang sudah ada: -* **If your app is already split into files that use `import` statements,** try to use the setup you already have. Check whether writing `
    ` in your JS code causes a syntax error. If it causes a syntax error, you might need to [transform your JavaScript code with Babel](https://babeljs.io/setup), and enable the [Babel React preset](https://babeljs.io/docs/babel-preset-react) to use JSX. +* **Jika aplikasi Anda sudah dipecah menjadi beberapa file yang menggunakan pernyataan `import`,** coba gunakan pengaturan yang sudah Anda miliki. Periksa apakah menulis `
    ` dalam kode JS Anda menyebabkan kesalahan sintaksis. Jika menyebabkan kesalahan sintaksis, Anda mungkin perlu [mengubah kode JavaScript Anda dengan Babel](https://babeljs.io/setup), dan mengaktifkan [Babel React preset](https://babeljs.io/docs/babel-preset-react) untuk menggunakan JSX. -* **If your app doesn't have an existing setup for compiling JavaScript modules,** set it up with [Vite](https://vitejs.dev/). The Vite community maintains [many integrations with backend frameworks](https://github.com/vitejs/awesome-vite#integrations-with-backends), including Rails, Django, and Laravel. If your backend framework is not listed, [follow this guide](https://vitejs.dev/guide/backend-integration.html) to manually integrate Vite builds with your backend. +* **Jika aplikasi Anda belum memiliki penyiapan untuk mengompilasi modul JavaScript,** siapkan dengan [Vite](https://vitejs.dev/). Komunitas Vite mempunyai [banyak integrasi *framework backend*](https://github.com/vitejs/awesome-vite#integrations-with-backends), termasuk Rails, Django, dan Laravel. Jika *framework backend* Anda tidak tercantum, [ikuti panduan ini](https://vitejs.dev/guide/backend-integration.html) untuk mengintegrasikan Vite build dengan backend Anda secara manual. -To check whether your setup works, run this command in your project folder: +Untuk memeriksa apakah penyiapan Anda berfungsi, jalankan perintah ini di folder proyek Anda: npm install react react-dom -Then add these lines of code at the top of your main JavaScript file (it might be called `index.js` or `main.js`): +Kemudian tambahkan baris kode ini di bagian atas file JavaScript utama Anda (mungkin disebut `index.js` atau `main.js`): @@ -62,7 +62,7 @@ Then add these lines of code at the top of your main JavaScript file (it might b My app - + ``` @@ -70,44 +70,44 @@ Then add these lines of code at the top of your main JavaScript file (it might b ```js index.js active import { createRoot } from 'react-dom/client'; -// Clear the existing HTML content +// Hapus konten HTML yang ada document.body.innerHTML = '
    '; -// Render your React component instead +// Render komponen React Anda sebagai gantinya const root = createRoot(document.getElementById('app')); root.render(

    Hello, world

    ); ```
    -If the entire content of your page was replaced by a "Hello, world!", everything worked! Keep reading. +Jika seluruh konten halaman Anda berganti dengan "Hello, world", semuanya berhasil! Teruslah membaca. -Integrating a modular JavaScript environment into an existing project for the first time can feel intimidating, but it's worth it! If you get stuck, try our [community resources](/community) or the [Vite Chat](https://chat.vitejs.dev/). +Mengintegrasikan lingkungan JavaScript modular ke dalam proyek yang sudah ada untuk pertama kalinya bisa terasa menakutkan, tetapi itu sepadan! Jika Anda mengalami kebuntuan, coba periksa [komunitas kami](/community) atau [Vite Chat](https://chat.vitejs.dev/). -### Step 2: Render React components anywhere on the page {/*step-2-render-react-components-anywhere-on-the-page*/} +### Langkah 2: Render komponen React di mana saja di halaman Anda {/*step-2-render-react-components-anywhere-on-the-page*/} -In the previous step, you put this code at the top of your main file: +Pada langkah sebelumnya, Anda meletakkan kode ini di bagian atas file utama Anda: ```js import { createRoot } from 'react-dom/client'; -// Clear the existing HTML content +// Hapus konten HTML yang ada document.body.innerHTML = '
    '; -// Render your React component instead +// Render komponen React Anda sebagai gantinya const root = createRoot(document.getElementById('app')); root.render(

    Hello, world

    ); ``` -Of course, you don't actually want to clear the existing HTML content! +Tentu saja, Anda sebenarnya tidak ingin menghapus konten HTML yang ada! -Delete this code. +Hapus kode ini. -Instead, you probably want to render your React components in specific places in your HTML. Open your HTML page (or the server templates that generate it) and add a unique [`id`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id) attribute to any tag, for example: +Sebagai gantinya, Anda mungkin ingin me-*render* komponen React Anda di tempat tertentu di HTML Anda. Buka halaman HTML Anda (atau *template server* yang membuatnya) dan tambahkan atribut [`id`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id) yang unik ke tag mana saja, sebagi contohnya: ```html @@ -115,7 +115,7 @@ Instead, you probably want to render your React components in specific places in ``` -This lets you find that HTML element with [`document.getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) and pass it to [`createRoot`](/reference/react-dom/client/createRoot) so that you can render your own React component inside: +Ini memungkinkan Anda menemukan elemen HTML dengan [`document.getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) dan meneruskannya ke [`createRoot`](/reference/react-dom/client/createRoot) sehingga Anda dapat me-*render* komponen React Anda sendiri di dalam: @@ -146,10 +146,10 @@ root.render(); -Notice how the original HTML content from `index.html` is preserved, but your own `NavigationBar` React component now appears inside the `