diff --git a/src/content/learn/sharing-state-between-components.md b/src/content/learn/sharing-state-between-components.md index 149164fe1..43f10e06f 100644 --- a/src/content/learn/sharing-state-between-components.md +++ b/src/content/learn/sharing-state-between-components.md @@ -1,31 +1,33 @@ --- -title: Sharing State Between Components +title: Berbagi State Antar Komponen --- -Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as *lifting state up,* and it's one of the most common things you will do writing React code. +Terkadang, Anda ingin dua komponen selalu berubah secara bersamaan. Untuk melakukannya, hapus *state* dari kedua komponen, pindahkan ke komponen induk terdekat, dan kemudian oper ke komponen tersebut melalui *props*. Ini dikenal sebagai *mengangkat state ke atas*, dan ini adalah salah satu hal yang paling umum yang akan Anda lakukan saat menulis kode React. -- How to share state between components by lifting it up -- What are controlled and uncontrolled components +- Bagaimana cara berbagi *state* antar komponen dengan menaikkan *state* ke atas (*lifting state up*) +- Apa itu komponen terkendali (*controlled component*) dan tak terkendali (*uncontrolled component*) -## Lifting state up by example {/*lifting-state-up-by-example*/} +## Contoh Mengangkat State Keatas {/*lifting-state-up-by-example*/} -In this example, a parent `Accordion` component renders two separate `Panel`s: + +Pada contoh ini, komponen induk `Accordion` merender dua komponen `Panel` terpisah: * `Accordion` - `Panel` - `Panel` -Each `Panel` component has a boolean `isActive` state that determines whether its content is visible. +Setiap komponen `Panel` memiliki *state* *boolean* `isActive` yang menentukan apakah kontennya terlihat. + -Press the Show button for both panels: +Tekan tombol Tampilkan untuk kedua panel: @@ -41,7 +43,7 @@ function Panel({ title, children }) {

{children}

) : ( )} @@ -52,11 +54,11 @@ export default function Accordion() { return ( <>

Almaty, Kazakhstan

- - With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. + + Dengan populasi sekitar 2 juta, Almaty adalah kota terbesar di Kazakhstan. Dari tahun 1929 hingga 1997, itu adalah ibu kota negara tersebut. - - The name comes from алма, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple. + + Nama berasal dari алма, kata Kazakh untuk "apel" dan sering diterjemahkan sebagai "penuh dengan apel". Faktanya, wilayah sekitar Almaty dipercaya sebagai rumah leluhur apel, dan tanaman liar Malus sieversii dianggap sebagai kandidat yang mungkin untuk leluhur apel domestik modern. ); @@ -73,59 +75,64 @@ h3, p { margin: 5px 0px; }
-Notice how pressing one panel's button does not affect the other panel--they are independent. +Perhatikan bagaimana menekan tombol satu panel tidak memengaruhi panel lainnya--mereka independen. - + -Initially, each `Panel`'s `isActive` state is `false`, so they both appear collapsed + +Awalnya, setiap `Panel` memiliki state `isActive` dengan nilai `false`, sehingga keduanya terlihat tertutup - + + -Clicking either `Panel`'s button will only update that `Panel`'s `isActive` state alone +Menekan tombol `Panel` mana pun hanya akan memperbarui *state* `isActive` dari `Panel` itu sendiri -**But now let's say you want to change it so that only one panel is expanded at any given time.** With that design, expanding the second panel should collapse the first one. How would you do that? +**Tetapi sekarang katakanlah Anda ingin mengubah panel tersebut sehingga hanya satu panel yang dibuka pada satu waktu.** Dengan desain di atas, membuka panel kedua berarti secara otomatis menutup panel pertama. Bagaimanakah Anda akan melakukannya? -To coordinate these two panels, you need to "lift their state up" to a parent component in three steps: +Untuk mengkoordinasikan kedua panel ini, Anda perlu "mengangkat *state* mereka" ke komponen induk dalam tiga langkah: -1. **Remove** state from the child components. -2. **Pass** hardcoded data from the common parent. -3. **Add** state to the common parent and pass it down together with the event handlers. +1. **Hapus** *state* dari komponen anak. +2. **Oper** data yang dituliskan langsung di dalam kode (*hardcoded*) dari komponen induk. +3. **Tambahkan** *state* ke komponen induk dan oper bersamaan dengan *event handlers*. -This will allow the `Accordion` component to coordinate both `Panel`s and only expand one at a time. +Cara ini akan memungkinkan komponen `Accordion` untuk mengkoordinasikan kedua `Panel` dan hanya membuka satu panel pada satu waktu. -### Step 1: Remove state from the child components {/*step-1-remove-state-from-the-child-components*/} +### Langkah 1: Hapus state dari komponen anak {/*step-1-remove-state-from-the-child-components*/} -You will give control of the `Panel`'s `isActive` to its parent component. This means that the parent component will pass `isActive` to `Panel` as a prop instead. Start by **removing this line** from the `Panel` component: + +Anda akan memberikan kontrol `isActive` dari `Panel` ke komponen induknya. Ini berarti komponen induk akan mengoper `isActive` ke `Panel` sebagai *prop*. Mulai dengan **menghapus baris ini** dari komponen `Panel`: ```js const [isActive, setIsActive] = useState(false); ``` -And instead, add `isActive` to the `Panel`'s list of props: +Lalu, tambahkan `isActive` ke daftar *prop* `Panel`: ```js -function Panel({ title, children, isActive }) { +function Panel({ title, children, isActive }) ``` -Now the `Panel`'s parent component can *control* `isActive` by [passing it down as a prop.](/learn/passing-props-to-a-component) Conversely, the `Panel` component now has *no control* over the value of `isActive`--it's now up to the parent component! +Sekarang komponen induk `Panel` dapat *mengontrol* `isActive` dengan [mengoper sebagai prop.](/learn/passing-props-to-a-component) Sebaliknya, komponen `Panel` sekarang tidak memiliki *kontrol* atas nilai `isActive`--sekarang terserah komponen induk! + -### Step 2: Pass hardcoded data from the common parent {/*step-2-pass-hardcoded-data-from-the-common-parent*/} +### Langkah 2: Oper data yang dituliskan langsung di dalam kode dari komponen induk {/*step-2-pass-hardcoded-data-from-the-common-parent*/} -To lift state up, you must locate the closest common parent component of *both* of the child components that you want to coordinate: +Untuk mengangkat *state*, Anda harus menemukan komponen induk yang paling dekat dari *kedua* komponen anak yang ingin Anda koordinasikan: -* `Accordion` *(closest common parent)* +* `Accordion` *(komponen induk terdekat)* - `Panel` - `Panel` -In this example, it's the `Accordion` component. Since it's above both panels and can control their props, it will become the "source of truth" for which panel is currently active. Make the `Accordion` component pass a hardcoded value of `isActive` (for example, `true`) to both panels: +Pada contoh ini, komponen `Accordion` adalah yang terdekat. Karena komponen ini berada di atas kedua panel dan dapat mengontrol *prop* mereka, komponen ini akan menjadi "sumber kebenaran" untuk panel mana yang sedang aktif. Buat komponen `Accordion` mengoper nilai `isActive` yang telah ditentukan sebelumnya (misalnya, `true`) ke kedua panel: + @@ -136,11 +143,11 @@ export default function Accordion() { return ( <>

Almaty, Kazakhstan

- - With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city. + + Dengan populasi sekitar 2 juta, Almaty adalah kota terbesar di Kazakhstan. Dari tahun 1929 hingga 1997, itu adalah ibu kota negara tersebut. - - The name comes from алма, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple. + + Nama berasal dari алма, kata Kazakh untuk "apel" dan sering diterjemahkan sebagai "penuh dengan apel". Faktanya, wilayah sekitar Almaty dipercaya sebagai rumah leluhur apel, dan Malus sieversii si liar dianggap sebagai kandidat yang mungkin untuk leluhur apel domestik modern. ); @@ -154,7 +161,7 @@ function Panel({ title, children, isActive }) {

{children}

) : ( )} @@ -172,21 +179,23 @@ h3, p { margin: 5px 0px; }
-Try editing the hardcoded `isActive` values in the `Accordion` component and see the result on the screen. +Coba ubah nilai `isActive` yang dituliskan langsung di dalam kode komponen `Accordion` dan lihat hasilnya di layar. + +### Langkah 3: Tambahkan state ke komponen induk {/*step-3-add-state-to-the-common-parent*/} + +Memindahkan *state* ke atas seringkali mengubah sifat dari apa yang Anda simpan sebagai *state*. -### Step 3: Add state to the common parent {/*step-3-add-state-to-the-common-parent*/} -Lifting state up often changes the nature of what you're storing as state. -In this case, only one panel should be active at a time. This means that the `Accordion` common parent component needs to keep track of *which* panel is the active one. Instead of a `boolean` value, it could use a number as the index of the active `Panel` for the state variable: +Dalam contoh ini, Anda ingin mengubah `Accordion` sehingga hanya satu panel yang dapat dibuka pada satu waktu. Ini berarti bahwa komponen induk `Accordion` perlu melacak *panel mana* yang sedang aktif. Alih-alih nilai `boolean`, ia dapat menggunakan angka sebagai indeks `Panel` aktif untuk variabel *state*: ```js const [activeIndex, setActiveIndex] = useState(0); ``` -When the `activeIndex` is `0`, the first panel is active, and when it's `1`, it's the second one. +Ketika `activeIndex` bernilai `0`, panel pertama aktif, dan ketika bernilai `1`, panel kedua aktif. -Clicking the "Show" button in either `Panel` needs to change the active index in `Accordion`. A `Panel` can't set the `activeIndex` state directly because it's defined inside the `Accordion`. The `Accordion` component needs to *explicitly allow* the `Panel` component to change its state by [passing an event handler down as a prop](/learn/responding-to-events#passing-event-handlers-as-props): +Menekan tombol "Tampilkan" di salah satu `Panel` perlu mengubah indeks aktif di `Accordion`. Sebuah `Panel` tidak dapat mengatur *state* `activeIndex` secara langsung karena ia didefinisikan di dalam `Accordion`. Komponen `Accordion` perlu *secara ekplisit mengizinkan* komponen `Panel` untuk mengubah *state*-nya dengan [mengoper *event handler* sebagai prop](/learn/responding-to-events#passing-event-handlers-as-props): ```js <> @@ -205,7 +214,7 @@ Clicking the "Show" button in either `Panel` needs to change the active index in ``` -The ` )} @@ -266,19 +275,21 @@ h3, p { margin: 5px 0px; } -This completes lifting state up! Moving state into the common parent component allowed you to coordinate the two panels. Using the active index instead of two "is shown" flags ensured that only one panel is active at a given time. And passing down the event handler to the child allowed the child to change the parent's state. +Dengan ini, terselesaikanlah pengangkatan *state* ke atas! Memindahkan *state* ke komponen induk memungkinkan Anda untuk mengkoordinasikan kedua panel. Menggunakan indeks aktif alih-alih dua *flag* "ditampilkan" memastikan bahwa hanya satu panel yang aktif pada satu waktu. Dan mengoper *event handler* ke komponen anak memungkinkan komponen anak untuk mengubah *state* induknya. - + -Initially, `Accordion`'s `activeIndex` is `0`, so the first `Panel` receives `isActive = true` + +Awalnya, nilai `activeIndex` dari `Accordion` adalah `0`, sehingga `Panel` pertama menerima `isActive = true` - + + -When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receives `isActive = true` instead +Ketika nilai `activeIndex` dari `Accordion` berubah menjadi `1`, `Panel` kedua menerima `isActive = true` sebagai gantinya @@ -286,48 +297,48 @@ When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receiv -#### Controlled and uncontrolled components {/*controlled-and-uncontrolled-components*/} +#### Komponen terkendali dan tak terkendali {/*controlled-and-uncontrolled-components*/} -It is common to call a component with some local state "uncontrolled". For example, the original `Panel` component with an `isActive` state variable is uncontrolled because its parent cannot influence whether the panel is active or not. +Secara umum Anda dapat menyebut sebuah komponen yang memiliki *state* lokal sebagai "tak terkendali". Misalnya, komponen `Panel` yang asli dengan variabel *state* `isActive` adalah tak terkendali karena induknya tidak dapat mempengaruhi apakah panel aktif atau tidak. -In contrast, you might say a component is "controlled" when the important information in it is driven by props rather than its own local state. This lets the parent component fully specify its behavior. The final `Panel` component with the `isActive` prop is controlled by the `Accordion` component. +Sebaliknya, Anda dapat menyebut sebuah komponen "terkendali" ketika informasi penting di dalamnya dikendalikan oleh *prop* daripada *state* lokalnya sendiri. Ini memungkinkan komponen induk untuk sepenuhnya menentukan perilakunya. Komponen `Panel` akhir dengan *prop* `isActive` dikendalikan oleh komponen `Accordion`. -Uncontrolled components are easier to use within their parents because they require less configuration. But they're less flexible when you want to coordinate them together. Controlled components are maximally flexible, but they require the parent components to fully configure them with props. +Komponen-komponen tak terkendali lebih mudah digunakan dalam induknya karena membutuhkan konfigurasi yang lebih sedikit. Tetapi mereka kurang fleksibel ketika Anda ingin mengkoordinasikannya bersamaan. Komponen-komponen terkendali sepenuhnya fleksibel, tetapi mereka membutuhkan komponen induk untuk sepenuhnya mengkonfigurasi mereka dengan *props*. -In practice, "controlled" and "uncontrolled" aren't strict technical terms--each component usually has some mix of both local state and props. However, this is a useful way to talk about how components are designed and what capabilities they offer. +Pada praktiknya, "terkendali" dan "tak terkendali" bukanlah istilah teknis yang ketat--setiap komponen biasanya memiliki beberapa campuran dari kedua *state* lokal dan *props*. Namun, ini adalah cara yang berguna untuk berbicara tentang bagaimana komponen dirancang dan kemampuan apa yang mereka tawarkan. -When writing a component, consider which information in it should be controlled (via props), and which information should be uncontrolled (via state). But you can always change your mind and refactor later. +Ketika menulis komponen, pertimbangkan informasi manakah di dalamnya yang seharusnya dikendalikan (melalui *props*), dan informasi manakah yang seharusnya tak terkendali (melalui *state*). Tetapi Anda selalu dapat mengubah pikiran Anda dan melakukan refaktorasi belakangan. -## A single source of truth for each state {/*a-single-source-of-truth-for-each-state*/} +## Satu sumber kebenaran untuk setiap state {/*a-single-source-of-truth-for-each-state*/} -In a React application, many components will have their own state. Some state may "live" close to the leaf components (components at the bottom of the tree) like inputs. Other state may "live" closer to the top of the app. For example, even client-side routing libraries are usually implemented by storing the current route in the React state, and passing it down by props! +Pada aplikasi React, banyak komponen akan memiliki *state* mereka sendiri. Beberapa *state* mungkin "hidup" dekat dengan komponen daun (komponen di bagian bawah pohon) seperti masukan-masukan (*inputs*). *State* lainnya mungkin "hidup" lebih dekat ke bagian atas aplikasi. Misalnya, bahkan pustaka-pustaka rute pada sisi klien (*client-side routing libraries*) biasanya diimplementasikan dengan menyimpan rute saat ini di *state* React, dan mengopernya dengan *props*! -**For each unique piece of state, you will choose the component that "owns" it.** This principle is also known as having a ["single source of truth".](https://en.wikipedia.org/wiki/Single_source_of_truth) It doesn't mean that all state lives in one place--but that for _each_ piece of state, there is a _specific_ component that holds that piece of information. Instead of duplicating shared state between components, *lift it up* to their common shared parent, and *pass it down* to the children that need it. +**Untuk setiap potongan *state* yang unik, Anda akan memilih komponen yang "memilikinya".** Prinsip ini juga dikenal sebagai memiliki ["sumber kebenaran tunggal".](https://en.wikipedia.org/wiki/Single_source_of_truth) Ini tidak berarti bahwa semua *state* berada di satu tempat--tetapi bahwa untuk _setiap_ potongan *state*, ada _komponen_ tertentu yang memegang potongan informasi itu. Alih-alih menduplikasi *state* yang sama diantara komponen, *angkatlah* *state* tersebut ke induk mereka, dan oper ke anak-anak yang membutuhkannya. -Your app will change as you work on it. It is common that you will move state down or back up while you're still figuring out where each piece of the state "lives". This is all part of the process! +Aplikasi Anda akan berubah saat Anda mengerjakannya. Biasanya Anda akan memindahkan *state* ke bawah atau kembali ke atas saat Anda masih mencari tahu di mana setiap potongan *state* "hidup". Semua ini adalah bagian dari proses! -To see what this feels like in practice with a few more components, read [Thinking in React.](/learn/thinking-in-react) +Untuk mengetahui bagaimana penerapannya dalam praktik dengan beberapa komponen lebih banyak, baca [Berpikir dalam React.](/learn/thinking-in-react) -* When you want to coordinate two components, move their state to their common parent. -* Then pass the information down through props from their common parent. -* Finally, pass the event handlers down so that the children can change the parent's state. -* It's useful to consider components as "controlled" (driven by props) or "uncontrolled" (driven by state). +* Ketika Anda ingin mengkoordinasikan dua komponen, pindahkan *state* mereka ke induknya. +* Kemudian oper informasi yang diperlukan melalui *props* dari induk mereka. +* Terakhir, oper *event handler* sehingga komponen anak-anak dapat mengubah *state* induk. +* Dapat membantu jika Anda mempertimbangkan komponen sebagai "terkendali" (dikendalikan oleh *props*) atau "tak terkendali" (dikendalikan oleh *state*). -#### Synced inputs {/*synced-inputs*/} +#### Masukan yang disinkronkan {/*synced-inputs*/} -These two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa. +Berikut ini dua masukan yang independen. Buat mereka tetap disinkronkan: mengedit satu masukan harus memperbarui masukan lain dengan teks yang sama, dan sebaliknya. -You'll need to lift their state up into the parent component. +Anda harus mengangkat *state* mereka ke komponen induk. @@ -339,8 +350,8 @@ import { useState } from 'react'; export default function SyncedInputs() { return ( <> - - + + ); } @@ -374,7 +385,7 @@ label { display: block; } -Move the `text` state variable into the parent component along with the `handleChange` handler. Then pass them down as props to both of the `Input` components. This will keep them in sync. +Pindahkan variabel *state* `text` ke komponen induk bersama dengan *event handler* `handleChange`. Kemudian oper mereka sebagai *props* ke kedua komponen `Input`. Ini akan membuat mereka tetap disinkronkan. @@ -391,12 +402,12 @@ export default function SyncedInputs() { return ( <> @@ -427,17 +438,18 @@ label { display: block; } -#### Filtering a list {/*filtering-a-list*/} +#### Memfilter daftar {/*filtering-a-list*/} + +Pada contoh ini, `SearchBar` memiliki *state* `query` sendiri yang mengontrol masukan teks. Komponen induknya `FilterableList` menampilkan `List` item, tetapi tidak memperhitungkan kueri pencarian. -In this example, the `SearchBar` has its own `query` state that controls the text input. Its parent `FilterableList` component displays a `List` of items, but it doesn't take the search query into account. -Use the `filterItems(foods, query)` function to filter the list according to the search query. To test your changes, verify that typing "s" into the input filters down the list to "Sushi", "Shish kebab", and "Dim sum". +Gunakan fungsi `filterItems(foods, query)` untuk memfilter daftar sesuai dengan kueri pencarian. Untuk menguji perubahan Anda, verifikasi bahwa mengetik "s" ke dalam masukan memfilter daftar menjadi "Sushi", "Shish kebab", dan "Dim sum". -Note that `filterItems` is already implemented and imported so you don't need to write it yourself! +Ingat bahwa `filterItems` sudah diimplementasikan dan diimport sehingga Anda tidak perlu menulisnya sendiri! -You will want to remove the `query` state and the `handleChange` handler from the `SearchBar`, and move them to the `FilterableList`. Then pass them down to `SearchBar` as `query` and `onChange` props. +Anda harus menghapus *state* `query` dan *event handler* `handleChange` dari `SearchBar`, dan memindahkannya ke `FilterableList`. Kemudian oper mereka ke `SearchBar` sebagai *props* `query` dan `onChange`. @@ -504,23 +516,23 @@ export function filterItems(items, query) { export const foods = [{ id: 0, name: 'Sushi', - description: 'Sushi is a traditional Japanese dish of prepared vinegared rice' + description: 'Sushi adalah hidangan Jepang tradisional dari nasi yang diawetkan dengan cuka.' }, { id: 1, name: 'Dal', - description: 'The most common way of preparing dal is in the form of a soup to which onions, tomatoes and various spices may be added' + description: 'Cara paling umum untuk menyiapkan dal adalah dalam bentuk sup yang dapat ditambahkan bawang bombay, tomat, dan berbagai bumbu.' }, { id: 2, name: 'Pierogi', - description: 'Pierogi are filled dumplings made by wrapping unleavened dough around a savoury or sweet filling and cooking in boiling water' + description: 'Pierogi adalah pangsit isi yang dibuat dengan cara membungkus adonan tidak beragi di sekitar isian yang gurih atau manis dan dimasak dalam air mendidih.' }, { id: 3, name: 'Shish kebab', - description: 'Shish kebab is a popular meal of skewered and grilled cubes of meat.' + description: 'Shish kebab adalah makanan populer yang terdiri dari potongan daging yang ditusuk dan dipanggang.' }, { id: 4, name: 'Dim sum', - description: 'Dim sum is a large range of small dishes that Cantonese people traditionally enjoy in restaurants for breakfast and lunch' + description: 'Dim sum adalah berbagai macam hidangan kecil yang biasa dinikmati orang Kanton di restoran untuk sarapan dan makan siang' }]; ``` @@ -528,7 +540,7 @@ export const foods = [{ -Lift the `query` state up into the `FilterableList` component. Call `filterItems(foods, query)` to get the filtered list and pass it down to the `List`. Now changing the query input is reflected in the list: +Angkat *state* `query` ke komponen `FilterableList`. Panggil `filterItems(foods, query)` untuk mendapatkan daftar yang difilter dan oper ke `List`. Sekarang ubah masukan kueri tercermin dalam daftar: @@ -597,23 +609,23 @@ export function filterItems(items, query) { export const foods = [{ id: 0, name: 'Sushi', - description: 'Sushi is a traditional Japanese dish of prepared vinegared rice' + description: 'Sushi adalah hidangan Jepang tradisional dari nasi yang diawetkan dengan cuka.' }, { id: 1, name: 'Dal', - description: 'The most common way of preparing dal is in the form of a soup to which onions, tomatoes and various spices may be added' + description: 'Cara paling umum untuk menyiapkan dal adalah dalam bentuk sup yang dapat ditambahkan bawang bombay, tomat, dan berbagai bumbu.' }, { id: 2, name: 'Pierogi', - description: 'Pierogi are filled dumplings made by wrapping unleavened dough around a savoury or sweet filling and cooking in boiling water' + description: 'Pierogi adalah pangsit isi yang dibuat dengan cara membungkus adonan tidak beragi di sekitar isian yang gurih atau manis dan dimasak dalam air mendidih.' }, { id: 3, name: 'Shish kebab', - description: 'Shish kebab is a popular meal of skewered and grilled cubes of meat.' + description: 'Shish kebab adalah makanan populer yang terdiri dari potongan daging yang ditusuk dan dipanggang.' }, { id: 4, name: 'Dim sum', - description: 'Dim sum is a large range of small dishes that Cantonese people traditionally enjoy in restaurants for breakfast and lunch' + description: 'Dim sum adalah berbagai macam hidangan kecil yang biasa dinikmati orang Kanton di restoran untuk sarapan dan makan siang' }]; ```