From e4bb45d1a95d45d13bbaeac6ed8ae4e602961e9d Mon Sep 17 00:00:00 2001 From: Ridwan Maulana Date: Mon, 1 May 2023 21:48:52 +0700 Subject: [PATCH 001/787] docs: translation for scaling up with reducer and context (#364) Co-authored-by: M Haidar Hanif Co-authored-by: Zain Fathoni --- .../scaling-up-with-reducer-and-context.md | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/content/learn/scaling-up-with-reducer-and-context.md b/src/content/learn/scaling-up-with-reducer-and-context.md index 0281afcec1..acc66ef6cf 100644 --- a/src/content/learn/scaling-up-with-reducer-and-context.md +++ b/src/content/learn/scaling-up-with-reducer-and-context.md @@ -1,24 +1,24 @@ --- -title: Scaling Up with Reducer and Context +title: Peningkatan Skala dengan Reducer dan Context --- -Reducers let you consolidate a component's state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen. +Reducer memungkinkan Anda untuk mengonsolidasi logika pembaruan *state* komponen. *Context* memungkinkan Anda untuk mengirim informasi ke komponen lain yang lebih dalam. Anda dapat menggabungkan *reducer* dan *context* bersama-sama untuk mengelola *state* layar yang kompleks. -* How to combine a reducer with context -* How to avoid passing state and dispatch through props -* How to keep context and state logic in a separate file +* Bagaimana menggabungkan *reducer* dengan *context* +* Bagaimana menghindari mengoper *state* dan *dispatch* melalui *props* +* Bagaimana menjaga konteks dan logika *state* pada *file* terpisah -## Combining a reducer with context {/*combining-a-reducer-with-context*/} +## Menggabungkan *reducer* dengan *context* {/*combining-a-reducer-with-context*/} -In this example from [the introduction to reducers](/learn/extracting-state-logic-into-a-reducer), the state is managed by a reducer. The reducer function contains all of the state update logic and is declared at the bottom of this file: +Pada contoh dari [pengenalan *reducer*](/learn/extracting-state-logic-into-a-reducer), *state* dikelola oleh *reducer*. Fungsi *reducer* berisi semua logika pembaruan *state* dan dinyatakan di bagian bawah *file* ini: @@ -207,9 +207,9 @@ ul, li { margin: 0; padding: 0; } -A reducer helps keep the event handlers short and concise. However, as your app grows, you might run into another difficulty. **Currently, the `tasks` state and the `dispatch` function are only available in the top-level `TaskApp` component.** To let other components read the list of tasks or change it, you have to explicitly [pass down](/learn/passing-props-to-a-component) the current state and the event handlers that change it as props. +*Reducer* membantu menjaga event handlers menjadi singkat dan ringkas. Namun, ketika aplikasi Anda berkembang, Anda mungkin akan menemukan kesulitan lain. Saat ini, *state* `tasks` dan fungsi `dispatch` hanya tersedia di komponen `TaskApp` level atas. Untuk memungkinkan komponen lain membaca daftar tugas atau mengubahnya, Anda harus secara eksplisit [meneruskan](/learn/passing-props-to-a-component) *state* saat ini dan event handlers yang mengubahnya sebagai props. -For example, `TaskApp` passes a list of tasks and the event handlers to `TaskList`: +Misalnya, `TaskApp` meneruskan daftar tugas dan *event handlers* ke `TaskList`: ```js ``` -And `TaskList` passes the event handlers to `Task`: +Dan `TaskList` mengoper *event handlers* ke `Task`: ```js ``` -In a small example like this, this works well, but if you have tens or hundreds of components in the middle, passing down all state and functions can be quite frustrating! +Dalam contoh kecil seperti ini, cara ini dapat berfungsi dengan baik, namun jika Anda memiliki puluhan atau ratusan komponen di tengah, meneruskan semua *state* dan fungsi dapat sangat menjengkelkan! -This is why, as an alternative to passing them through props, you might want to put both the `tasks` state and the `dispatch` function [into context.](/learn/passing-data-deeply-with-context) **This way, any component below `TaskApp` in the tree can read the tasks and dispatch actions without the repetitive "prop drilling".** +Inilah mengapa, sebagai alternatif untuk melewatkan melalui props, Anda mungkin ingin menempatkan baik *state* `tugas` maupun fungsi `dispatch` [ke dalam *context*](/learn/passing-data-deeply-with-context) . **Dengan cara ini, komponen apa pun di bawah `TaskApp` dalam pohon (*tree*) dapat membaca tugas dan melakukan aksi *dispatch* tanpa “*prop drilling*” yang berulang.** -Here is how you can combine a reducer with context: +Berikut adalah cara menggabungkan *reducer* dengan conteks: -1. **Create** the context. -2. **Put** state and dispatch into context. -3. **Use** context anywhere in the tree. +1. **Buatlah** *context*. +2. **Letakkan** *state* dan *dispatch* ke dalam *context*. +3. **Gunakan** *context* di mana saja dalam *tree*. -### Step 1: Create the context {/*step-1-create-the-context*/} +### Langkah 1: Buat context {/*step-1-create-the-context*/} -The `useReducer` Hook returns the current `tasks` and the `dispatch` function that lets you update them: +Hook `useReducer` mengembalikan `tasks` saat ini dan fungsi `dispatch` yang memungkinkan Anda memperbaruinya: ```js const [tasks, dispatch] = useReducer(tasksReducer, initialTasks); ``` -To pass them down the tree, you will [create](/learn/passing-data-deeply-with-context#step-2-use-the-context) two separate contexts: +Untuk meneruskannya ke dalam *tree*, Anda akan [membuat](/learn/passing-data-deeply-with-context#step-2-use-the-context) dua *context* terpisah: -- `TasksContext` provides the current list of tasks. -- `TasksDispatchContext` provides the function that lets components dispatch actions. +- `TasksContext` menyediakan daftar tugas saat ini. +- `TasksDispatchContext` menyediakan fungsi yang memungkinkan komponen melakukan aksi *dispatch*. -Export them from a separate file so that you can later import them from other files: +Kemudian ekspor keduanya dari *file* terpisah agar nantinya dapat diimpor dari *file* lain: @@ -448,11 +448,11 @@ ul, li { margin: 0; padding: 0; } -Here, you're passing `null` as the default value to both contexts. The actual values will be provided by the `TaskApp` component. +Di sini, Anda meneruskan `null` sebagai nilai *default* ke kedua *context*. Nilai aktual akan disediakan oleh komponen `TaskApp`. -### Step 2: Put state and dispatch into context {/*step-2-put-state-and-dispatch-into-context*/} +### Langkah 2: Letakkan *state* dan *dispatch* ke dalam *context* {/*step-2-put-state-and-dispatch-into-context*/} -Now you can import both contexts in your `TaskApp` component. Take the `tasks` and `dispatch` returned by `useReducer()` and [provide them](/learn/passing-data-deeply-with-context#step-3-provide-the-context) to the entire tree below: +Sekarang Anda dapat mengimpor kedua *context* di komponen `TaskApp` Anda. Ambil `tasks` dan `dispatch` yang dikembalikan oleh `useReducer()` dan [sediakan mereka](/learn/passing-data-deeply-with-context#step-3-provide-the-context) kepada seluruh pohon (*tree*) di bawahnya: ```js {4,7-8} import { TasksContext, TasksDispatchContext } from './TasksContext.js'; @@ -470,7 +470,7 @@ export default function TaskApp() { } ``` -For now, you pass the information both via props and in context: +Saat ini, Anda meneruskan informasi baik melalui *props* maupun melalui *context*: @@ -669,11 +669,11 @@ ul, li { margin: 0; padding: 0; } -In the next step, you will remove prop passing. +Pada langkah selanjutnya, Anda akan menghapus pengoperan *prop*. -### Step 3: Use context anywhere in the tree {/*step-3-use-context-anywhere-in-the-tree*/} +### Langkah 3: Gunakan *context* di mana saja dalam pohon {/*step-3-use-context-anywhere-in-the-tree*/} -Now you don't need to pass the list of tasks or the event handlers down the tree: +Sekarang Anda tidak perlu lagi meneruskan daftar tugas atau *event handler* ke bawah pohon: ```js {4-5} @@ -685,7 +685,7 @@ Now you don't need to pass the list of tasks or the event handlers down the tree ``` -Instead, any component that needs the task list can read it from the `TaskContext`: +Sebaliknya, komponen mana pun yang memerlukan daftar tugas dapat membacanya dari `TaskContext`: ```js {2} export default function TaskList() { @@ -693,7 +693,7 @@ export default function TaskList() { // ... ``` -To update the task list, any component can read the `dispatch` function from context and call it: +Untuk memperbarui daftar tugas, komponen mana pun dapat membaca fungsi `dispatch` dari *context* dan memanggilnya: ```js {3,9-13} export default function AddTask() { @@ -713,7 +713,7 @@ export default function AddTask() { // ... ``` -**The `TaskApp` component does not pass any event handlers down, and the `TaskList` does not pass any event handlers to the `Task` component either.** Each component reads the context that it needs: +**Komponen `TaskApp` tidak meneruskan *event handler* ke bawah, dan `TaskList` juga tidak meneruskan event handler ke komponen `Task`.** Setiap komponen membaca *context* yang dibutuhkannya: @@ -897,11 +897,11 @@ ul, li { margin: 0; padding: 0; } -**The state still "lives" in the top-level `TaskApp` component, managed with `useReducer`.** But its `tasks` and `dispatch` are now available to every component below in the tree by importing and using these contexts. +***State* masih "berada" di dalam komponen `TaskApp` level atas, dikelola dengan `useReducer`.** Tetapi daftar `tasks` dan fungsi `dispatch` sekarang tersedia untuk setiap komponen di bawah pohon tersebut dengan mengimpor dan menggunakan *context* tersebut. -## Moving all wiring into a single file {/*moving-all-wiring-into-a-single-file*/} +## Memindahkan semua penghubung ke satu file {/*moving-all-wiring-into-a-single-file*/} -You don't have to do this, but you could further declutter the components by moving both reducer and context into a single file. Currently, `TasksContext.js` contains only two context declarations: +Anda tidak harus melakukannya, tetapi Anda dapat membersihkan komponen dengan memindahkan *reducer* dan *context* ke dalam satu file. Saat ini, `TasksContext.js` hanya berisi dua deklarasi *context*: ```js import { createContext } from 'react'; @@ -910,11 +910,11 @@ export const TasksContext = createContext(null); export const TasksDispatchContext = createContext(null); ``` -This file is about to get crowded! You'll move the reducer into that same file. Then you'll declare a new `TasksProvider` component in the same file. This component will tie all the pieces together: +*File* ini akan semakin ramai! Anda akan memindahkan *reducer* ke dalam *file* yang sama. Kemudian Anda akan mendeklarasikan komponen `TasksProvider` baru dalam *file* yang sama. Komponen ini akan mengikat semua bagian bersama-sama: -1. It will manage the state with a reducer. -2. It will provide both contexts to components below. -3. It will [take `children` as a prop](/learn/passing-props-to-a-component#passing-jsx-as-children) so you can pass JSX to it. +1. Ia akan mengelola *state* dengan *reducer*. +2. Ia akan menyediakan kedua *context* ke komponen di bawahnya. +3. Ia akan [mengambil *children* sebagai prop](/learn/passing-props-to-a-component#passing-jsx-as-children) sehingga Anda dapat mengoper JSX kepadanya. ```js export function TasksProvider({ children }) { @@ -930,7 +930,7 @@ export function TasksProvider({ children }) { } ``` -**This removes all the complexity and wiring from your `TaskApp` component:** +**Ini menghilangkan semua kompleksitas dan penghubung dari komponen `TaskApp` Anda:** @@ -1121,7 +1121,7 @@ ul, li { margin: 0; padding: 0; } -You can also export functions that _use_ the context from `TasksContext.js`: +Anda juga dapat mengekspor fungsi-fungsi yang *menggunakan* *context* dari `TasksContext.js`: ```js export function useTasks() { @@ -1133,14 +1133,14 @@ export function useTasksDispatch() { } ``` -When a component needs to read context, it can do it through these functions: +Ketika sebuah komponen perlu membaca *context*, dapat dilakukan melalui fungsi-fungsi ini: ```js const tasks = useTasks(); const dispatch = useTasksDispatch(); ``` -This doesn't change the behavior in any way, but it lets you later split these contexts further or add some logic to these functions. **Now all of the context and reducer wiring is in `TasksContext.js`. This keeps the components clean and uncluttered, focused on what they display rather than where they get the data:** +Hal ini tidak mengubah perilaku secara apa pun, tetapi memungkinkan Anda untuk memisahkan *context* ini lebih lanjut atau menambahkan beberapa logika ke fungsi-fungsi ini. **Sekarang semua pengaturan *context* dan *reducer* ada di `TasksContext.js`. Ini menjaga komponen tetap bersih dan tidak berantakan, fokus pada apa yang mereka tampilkan daripada dari mana mereka mendapatkan data:** @@ -1340,27 +1340,27 @@ ul, li { margin: 0; padding: 0; } -You can think of `TasksProvider` as a part of the screen that knows how to deal with tasks, `useTasks` as a way to read them, and `useTasksDispatch` as a way to update them from any component below in the tree. +Anda dapat memandang `TasksProvider` sebagai bagian dari layar yang tahu cara menangani tugas, `useTasks` sebagai cara untuk membacanya, dan `useTasksDispatch` sebagai cara untuk memperbaruinya dari komponen mana pun di bawah pohon. -Functions like `useTasks` and `useTasksDispatch` are called *[Custom Hooks.](/learn/reusing-logic-with-custom-hooks)* Your function is considered a custom Hook if its name starts with `use`. This lets you use other Hooks, like `useContext`, inside it. +Fungsi-fungsi seperti `useTasks` dan `useTasksDispatch` disebut dengan *[Hook Custom](/learn/reusing-logic-with-custom-hooks)*. Fungsi Anda dianggap sebagai *Hook custom* jika namanya dimulai dengan `use`. Ini memungkinkan Anda menggunakan Hooks lain, seperti `useContext`, di dalamnya. -As your app grows, you may have many context-reducer pairs like this. This is a powerful way to scale your app and [lift state up](/learn/sharing-state-between-components) without too much work whenever you want to access the data deep in the tree. +Seiring dengan pertumbuhan aplikasi Anda, mungkin Anda akan memiliki banyak pasangan *context-reducer* seperti ini. Ini adalah cara yang kuat untuk meningkatkan aplikasi Anda dan [mengangkat *state* ke atas](/learn/sharing-state-between-components) tanpa terlalu banyak pekerjaan setiap kali Anda ingin mengakses data yang dalam di dalam pohon (*tree*). -- You can combine reducer with context to let any component read and update state above it. -- To provide state and the dispatch function to components below: - 1. Create two contexts (for state and for dispatch functions). - 2. Provide both contexts from the component that uses the reducer. - 3. Use either context from components that need to read them. -- You can further declutter the components by moving all wiring into one file. - - You can export a component like `TasksProvider` that provides context. - - You can also export custom Hooks like `useTasks` and `useTasksDispatch` to read it. -- You can have many context-reducer pairs like this in your app. +- Anda dapat menggabungkan *reducer* dengan *context* untuk memungkinkan komponen mana pun membaca dan memperbarui *state* di atasnya. +- Untuk menyediakan *state* dan fungsi *dispatch* ke komponen di bawah: + 1. Buat dua *context* (untuk *state* dan untuk fungsi *dispatch*). + 2. Sediakan kedua *context* dari komponen yang menggunakan *reducer*. + 3. Gunakan salah satu *context* dari komponen yang perlu membacanya. +- Anda dapat memindahkan seluruh penghubung ke satu *file* untuk memperjelas komponen. + - Anda dapat mengekspor komponen seperti `TasksProvider` yang menyediakan *context*. + - Anda juga dapat mengekspor *Hooks Custom* seperti `useTasks` dan `useTasksDispatch` untuk membacanya. +- Anda dapat memiliki banyak pasangan *context-reducer* seperti ini di aplikasi Anda. From f27710371f20bebf93718ecbbbb6203e1768f75f Mon Sep 17 00:00:00 2001 From: Ujang Sarutobi <41730448+adamcanray@users.noreply.github.com> Date: Mon, 1 May 2023 21:50:21 +0700 Subject: [PATCH 002/787] docs: translation for useDeferredValue (#360) Co-authored-by: M Haidar Hanif Co-authored-by: RiN --- .../reference/react/useDeferredValue.md | 198 +++++++++--------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 3f2a8a5d9d..7a91778ed4 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -4,7 +4,7 @@ title: useDeferredValue -`useDeferredValue` is a React Hook that lets you defer updating a part of the UI. +`useDeferredValue` adalah React Hook yang memungkinkan Anda menangguhkan pembaruan bagian dari UI. ```js const deferredValue = useDeferredValue(value) @@ -16,11 +16,11 @@ const deferredValue = useDeferredValue(value) --- -## Reference {/*reference*/} +## Referensi {/*reference*/} ### `useDeferredValue(value)` {/*usedeferredvalue*/} -Call `useDeferredValue` at the top level of your component to get a deferred version of that value. +Panggil fungsi `useDeferredValue` di tingkat atas komponen Anda untuk mendapatkan versi yang ditangguhkan dari nilai tersebut. ```js import { useState, useDeferredValue } from 'react'; @@ -32,37 +32,37 @@ function SearchPage() { } ``` -[See more examples below.](#usage) +[Lihat contoh lainnya di bawah ini.](#usage) #### Parameters {/*parameters*/} -* `value`: The value you want to defer. It can have any type. +* `value`: Nilai yang ingin Anda tangguhkan. Nilai ini dapat memiliki tipe apa saja. #### Returns {/*returns*/} -During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value). +Selama render awal, nilai tangguhan yang dikembalikan akan sama dengan nilai yang Anda berikan. Selama pembaruan, React pertama-tama akan mencoba render ulang dengan nilai lama (sehingga akan mengembalikan nilai lama), dan kemudian mencoba render ulang lainnya di latar belakang dengan nilai baru (sehingga akan mengembalikan nilai yang diperbarui). #### Caveats {/*caveats*/} -- The values you pass to `useDeferredValue` should either be primitive values (like strings and numbers) or objects created outside of rendering. If you create a new object during rendering and immediately pass it to `useDeferredValue`, it will be different on every render, causing unnecessary background re-renders. +- Nilai yang Anda oper ke `useDeferredValue` harus berupa nilai primitif (seperti string dan angka) atau objek yang dibuat di luar *rendering*. Jika Anda membuat objek baru selama perenderan dan langsung mengopernya ke `useDeferredValue`, objek tersebut akan berbeda di setiap perenderan, menyebabkan render ulang latar belakang yang tidak perlu. -- When `useDeferredValue` receives a different value (compared with [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), in addition to the current render (when it still uses the previous value), it schedules a re-render in the background with the new value. The background re-render is interruptible: if there's another update to the `value`, React will restart the background re-render from scratch. For example, if the user is typing into an input faster than a chart receiving its deferred value can re-render, the chart will only re-render after the user stops typing. +- Ketika `useDeferredValue` menerima nilai yang berbeda (dibandingkan dengan [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), di selain render saat ini (ketika masih menggunakan nilai sebelumnya), ia menjadwalkan render ulang di latar belakang dengan nilai baru. Render ulang latar belakang dapat diinterupsi: jika ada pembaruan lain pada `value`, React akan memulai lagi render ulang latar belakang dari awal. Misalnya, jika pengguna mengetik input lebih cepat daripada bagan yang menerima nilai yang ditangguhkan dapat render ulang, bagan hanya akan render ulang setelah pengguna berhenti mengetik. -- `useDeferredValue` is integrated with [``.](/reference/react/Suspense) If the background update caused by a new value suspends the UI, the user will not see the fallback. They will see the old deferred value until the data loads. +- `useDeferredValue` terintegrasi dengan [``.](/reference/react/Suspense) Jika update latar belakang yang disebabkan oleh nilai baru menangguhkan UI, pengguna tidak akan melihat fallback. Mereka akan melihat nilai ditangguhkan yang lama hingga data dimuat. -- `useDeferredValue` does not by itself prevent extra network requests. +- `useDeferredValue` tidak dengan sendirinya mencegah permintaan jaringan tambahan. -- There is no fixed delay caused by `useDeferredValue` itself. As soon as React finishes the original re-render, React will immediately start working on the background re-render with the new deferred value. Any updates caused by events (like typing) will interrupt the background re-render and get prioritized over it. +- Tidak ada penundaan tetap yang disebabkan oleh `useDeferredValue` itu sendiri. Segera setelah React menyelesaikan render ulang asli, React akan segera mulai mengerjakan render ulang latar belakang dengan nilai baru yang ditangguhkan. Pembaruan apa pun yang disebabkan oleh peristiwa (seperti mengetik) akan mengganggu render ulang latar belakang dan mendapatkan prioritas di atasnya. -- The background re-render caused by `useDeferredValue` does not fire Effects until it's committed to the screen. If the background re-render suspends, its Effects will run after the data loads and the UI updates. +- Render ulang latar belakang yang disebabkan oleh `useDeferredValue` tidak mengaktifkan Efek hingga diterapkan ke layar. Jika render ulang latar belakang ditangguhkan, Efeknya akan berjalan setelah data dimuat dan pembaruan UI. --- -## Usage {/*usage*/} +## Penggunaan {/*usage*/} -### Showing stale content while fresh content is loading {/*showing-stale-content-while-fresh-content-is-loading*/} +### Menampilkan konten basi saat konten segar sedang dimuat {/*showing-stale-content-while-fresh-content-is-loading*/} -Call `useDeferredValue` at the top level of your component to defer updating some part of your UI. +Panggil fungsi `useDeferredValue` di tingkat atas komponen Anda untuk menangguhkan pembaruan beberapa bagian dari UI Anda. ```js [[1, 5, "query"], [2, 5, "deferredQuery"]] import { useState, useDeferredValue } from 'react'; @@ -74,25 +74,25 @@ function SearchPage() { } ``` -During the initial render, the deferred value will be the same as the value you provided. +Selama render awal, nilai yang ditangguhkan akan sama dengan nilai yang Anda berikan. -During updates, the deferred value will "lag behind" the latest value. In particular, React will first re-render *without* updating the deferred value, and then try to re-render with the newly received value in background. +Selama pembaruan, nilai yang ditangguhkan akan "tertinggal" dari nilai terbaru. Secara khusus, React pertama-tama akan render ulang *tanpa* memperbarui nilai yang ditangguhkan, dan kemudian mencoba render ulang dengan nilai yang baru diterima di latar belakang. -**Let's walk through an example to see when this is useful.** +**Mari telusuri contoh untuk melihat kapan ini berguna.** -This example assumes you use one of Suspense-enabled data sources: +Contoh ini menganggap Anda menggunakan salah satu sumber data yang menggunakan Suspense: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/advanced-features/react-18) -- Lazy-loading component code with [`lazy`](/reference/react/lazy) +- Pengambilan data yang menggunakan Suspense dengan framework seperti [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) dan [Next.js](https://nextjs.org/docs/advanced-features/react-18) +- Kode komponen pemuatan lambat dengan [`lazy`](/reference/react/lazy) -[Learn more about Suspense and its limitations.](/reference/react/Suspense) +[Pelajari lebih lanjut tentang Suspense dan batasannya.](/reference/react/Suspense) -In this example, the `SearchResults` component [suspends](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading) while fetching the search results. Try typing `"a"`, waiting for the results, and then editing it to `"ab"`. The results for `"a"` get replaced by the loading fallback. +Dalam contoh ini, komponen `SearchResults` [ditangguhkan](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading) saat mengambil hasil penelusuran. Coba ketik `"a"`, tunggu hasilnya, lalu edit menjadi `"ab"`. Hasil untuk `"a"` diganti dengan fallback pemuatan. @@ -120,10 +120,10 @@ export default function App() { return ( <> - Loading...}> + Memuat...}> @@ -134,11 +134,11 @@ export default function App() { ```js SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Catatan: komponen ini ditulis menggunakan API eksperimental +// itu belum tersedia di React versi stabil. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Untuk contoh realistis yang dapat Anda ikuti hari ini, cobalah kerangka kerja +// yang terintegrasi dengan Suspense, seperti Relay atau Next.js. export default function SearchResults({ query }) { if (query === '') { @@ -159,8 +159,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Ini adalah solusi untuk bug agar demo berjalan. +// TODO: ganti dengan implementasi nyata saat bug diperbaiki. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -186,9 +186,9 @@ function use(promise) { ``` ```js data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Catatan: cara Anda melakukan pengambilan data bergantung pada +// kerangka kerja yang Anda gunakan bersama Suspense. +// Biasanya, logika caching akan berada di dalam kerangka kerja. let cache = new Map(); @@ -208,7 +208,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. + // Tambahkan penundaan palsu agar menunggu terlihat. await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -284,7 +284,7 @@ input { margin: 10px; } -A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down: +Pola UI alternatif yang umum adalah *menangguhkan* pembaruan daftar hasil dan terus menampilkan hasil sebelumnya hingga hasil baru siap. Panggil `useDeferredValue` untuk meneruskan versi kueri yang ditangguhkan: ```js {3,11} export default function App() { @@ -293,10 +293,10 @@ export default function App() { return ( <> - Loading...}> + Memuat...}> @@ -304,9 +304,9 @@ export default function App() { } ``` -The `query` will update immediately, so the input will display the new value. However, the `deferredQuery` will keep its previous value until the data has loaded, so `SearchResults` will show the stale results for a bit. +`query` akan segera diperbarui, sehingga input akan menampilkan nilai baru. Namun, `deferredQuery` akan mempertahankan nilai sebelumnya sampai data telah dimuat, sehingga `SearchResults` akan menampilkan hasil lama untuk beberapa saat. -Enter `"a"` in the example below, wait for the results to load, and then edit the input to `"ab"`. Notice how instead of the Suspense fallback, you now see the stale result list until the new results have loaded: +Masukkan `"a"` pada contoh di bawah, tunggu hasil dimuat, lalu edit input menjadi `"ab"`. Perhatikan bagaimana alih-alih cadangan Suspense, Anda sekarang melihat daftar hasil basi hingga hasil baru dimuat: @@ -335,10 +335,10 @@ export default function App() { return ( <> - Loading...}> + Memuat...}> @@ -349,11 +349,11 @@ export default function App() { ```js SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// Catatan: komponen ini ditulis menggunakan API eksperimental +// itu belum tersedia di React versi stabil. -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// Untuk contoh realistis yang dapat Anda ikuti hari ini, cobalah kerangka kerja +// yang terintegrasi dengan Suspense, seperti Relay atau Next.js. export default function SearchResults({ query }) { if (query === '') { @@ -374,8 +374,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// Ini adalah solusi untuk bug agar demo berjalan. +// TODO: ganti dengan implementasi nyata saat bug diperbaiki. function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -401,9 +401,9 @@ function use(promise) { ``` ```js data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// Catatan: cara Anda melakukan pengambilan data bergantung pada +// kerangka kerja yang Anda gunakan bersama Suspense. +// Biasanya, logika caching akan berada di dalam kerangka kerja. let cache = new Map(); @@ -423,7 +423,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. + // Tambahkan penundaan palsu agar menunggu terlihat. await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -501,25 +501,25 @@ input { margin: 10px; } -#### How does deferring a value work under the hood? {/*how-does-deferring-a-value-work-under-the-hood*/} +#### Bagaimana menangguhkan nilai bekerja dibalik layar? {/*how-does-deferring-a-value-work-under-the-hood*/} -You can think of it as happening in two steps: +Anda dapat menganggapnya terjadi dalam dua langkah: -1. **First, React re-renders with the new `query` (`"ab"`) but with the old `deferredQuery` (still `"a")`.** The `deferredQuery` value, which you pass to the result list, is *deferred:* it "lags behind" the `query` value. +1. **Pertama, React me-*render* ulang dengan `query` (`"ab"` baru) tetapi dengan `deferredQuery` lama (masih `"a"`).** Nilai `deferredQuery`, yang Anda berikan ke daftar hasil, adalah *ditangguhkan:* itu "tertinggal" dari nilai `query`. -2. **In background, React tries to re-render with *both* `query` and `deferredQuery` updated to `"ab"`.** If this re-render completes, React will show it on the screen. However, if it suspends (the results for `"ab"` have not loaded yet), React will abandon this rendering attempt, and retry this re-render again after the data has loaded. The user will keep seeing the stale deferred value until the data is ready. +2. **Di latar belakang, React mencoba me-*render* ulang dengan *baik* `query` dan `deferredQuery` diperbarui ke `"ab"`.** Jika render ulang ini selesai, React akan menampilkannya di layar. Namun, jika ditangguhkan (hasil untuk `"ab"` belum dimuat), React akan mengabaikan upaya *rendering* ini, dan mencoba lagi render ulang ini setelah data dimuat. Pengguna akan terus melihat nilai yang ditangguhkan hingga data siap. -The deferred "background" rendering is interruptible. For example, if you type into the input again, React will abandon it and restart with the new value. React will always use the latest provided value. +Render "latar belakang" yang ditangguhkan dapat diinterupsi. Misalnya, jika Anda mengetik input lagi, React akan mengabaikannya dan memulai kembali dengan nilai baru. React akan selalu menggunakan nilai terbaru yang diberikan. -Note that there is still a network request per each keystroke. What's being deferred here is displaying results (until they're ready), not the network requests themselves. Even if the user continues typing, responses for each keystroke get cached, so pressing Backspace is instant and doesn't fetch again. +Perhatikan bahwa masih ada permintaan jaringan per setiap penekanan tombol. Apa yang ditangguhkan di sini adalah menampilkan hasil (sampai siap), bukan permintaan jaringan itu sendiri. Bahkan jika pengguna terus mengetik, respons untuk setiap ketukan tombol akan di-cache, sehingga menekan Backspace akan instan dan tidak mengambil lagi. --- -### Indicating that the content is stale {/*indicating-that-the-content-is-stale*/} +### Menandakan bahwa konten tersebut sudah basi {/*indicating-that-the-content-is-stale*/} -In the example above, there is no indication that the result list for the latest query is still loading. This can be confusing to the user if the new results take a while to load. To make it more obvious to the user that the result list does not match the latest query, you can add a visual indication when the stale result list is displayed: +Pada contoh di atas, tidak ada indikasi bahwa daftar hasil kueri terbaru masih dimuat. Ini dapat membingungkan pengguna jika hasil baru membutuhkan waktu untuk dimuat. Untuk membuatnya lebih jelas bagi pengguna bahwa daftar hasil tidak cocok dengan kueri terbaru, Anda dapat menambahkan indikasi visual saat daftar hasil basi ditampilkan: ```js {2}
``` -With this change, as soon as you start typing, the stale result list gets slightly dimmed until the new result list loads. You can also add a CSS transition to delay dimming so that it feels gradual, like in the example below: +Dengan perubahan ini, segera setelah Anda mulai mengetik, daftar hasil basi menjadi sedikit redup hingga daftar hasil baru dimuat. Anda juga bisa menambahkan transisi CSS untuk menangguhkan peredupan agar terasa bertahap, seperti pada contoh di bawah ini: @@ -559,10 +559,10 @@ export default function App() { return ( <> - Loading...}> + Memuat...}>