Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate Reconciliation #115

Merged
merged 2 commits into from
Dec 13, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 45 additions & 46 deletions content/docs/reconciliation.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
---
id: reconciliation
title: Reconciliation
title: Rekonsiliasi
permalink: docs/reconciliation.html
---

React provides a declarative API so that you don't have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React's "diffing" algorithm so that component updates are predictable while being fast enough for high-performance apps.
React menyediakan API deklaratif jadi Anda tidak perlu khawatir tentang apa yang pasti berubah pada setiap pembaruan. Ini membuat penulisan aplikasi menjadi jauh lebih mudah, tetapi ini mungkin kurang jelas bagaimana ini diimplementasikan di dalam React. Artikel ini menjelaskan pilihan yang bisa kita buat dalam algoritma "pembeda" nya React jadi pembaruan komponen dapat diprediksi selagi aplikasi berkinerja cukup cepat.

## Motivation {#motivation}
## Motivasi {#motivation}

When you use React, at a single point in time you can think of the `render()` function as creating a tree of React elements. On the next state or props update, that `render()` function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree.
Ketika Anda menggunakan React, pada satu titik waktu Anda dapat berpikir fungsi `render()` sebagai pembuat pohon elemen React. Pada pembaruan *state* atau *prop* selanjutnya, fungsi `render()` tersebut akan mengembalikan pohon elemen React yang berbeda. React kemudian perlu mencari tahu bagaimana cara untuk memperbarui antarmuka pengguna secara efisien agar sesuai dengan pohon terbaru.

There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the [state of the art algorithms](https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n<sup>3</sup>) where n is the number of elements in the tree.
Ada beberapa solusi umum untuk permasalahan algoritma ini menghasilkan jumlah operasi minimum untuk mengubah satu pohon ke yang lain. Namun, The [State of the Art Algorithms](https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) memiliki kompleksitas dalam urutan O(n<sup>3</sup>) dimana n adalah jumlah elemen di pohon.

If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:
Jika kita menggunakannya di React, menampilkan 1000 elemen akan membutuhkan satu miliar perbandingan. Ini terlalu mahal. Sebagai gantinya, React mengimplementasikan algoritma heuristik O(n) berdasarkan dua asumsi:

1. Two elements of different types will produce different trees.
2. The developer can hint at which child elements may be stable across different renders with a `key` prop.
1. Dua elemen yang berbeda jenis akan menghasilkan pohon-pohon yang berbeda.
2. Pengembang dapat mengisyaratkan elemen *child* mana yang mungkin stabil di berbagai *render* yang berbeda dengan *prop* `key`.

In practice, these assumptions are valid for almost all practical use cases.
Dalam prakteknya, asumsi ini sah untuk hampir semua contoh kasus praktis.

## The Diffing Algorithm {#the-diffing-algorithm}
## Algoritma Pembeda {#the-diffing-algorithm}

When diffing two trees, React first compares the two root elements. The behavior is different depending on the types of the root elements.
Saat membedakan dua pohon, React pertama membandingkan dua elemen *root*. Tindakan berbeda tergantung pada jenis dari elemen-elemen *root*.

### Elements Of Different Types {#elements-of-different-types}
### Elemen Dari Berbagai Jenis {#elements-of-different-types}

Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from `<a>` to `<img>`, or from `<Article>` to `<Comment>`, or from `<Button>` to `<div>` - any of those will lead to a full rebuild.
Kapanpun elemen-elemen *root* memiliki jenis yang berbeda, React akan meruntuhkan pohon lama dan membangun pohon baru dari awal. Mulai dari `<a>` ke `<img>`, atau dari `<Article>` ke `<Comment>`, atau dari `<Button>` ke `<div>` - Semua itu akan mengarah pada pembangunan kembali sepenuhnya.

When tearing down a tree, old DOM nodes are destroyed. Component instances receive `componentWillUnmount()`. When building up a new tree, new DOM nodes are inserted into the DOM. Component instances receive `componentWillMount()` and then `componentDidMount()`. Any state associated with the old tree is lost.
Saat meruntuhkan sebuah pohon, node DOM lama dihancurkan. *Instance* komponen menerima `componentWillUnmount()`. Saat membangun pohon baru, node DOM baru dimasukan ke dalam DOM. *Instance* komponen menerima `componentWillMount()` lalu `componentDidMount()`. *State* manapun yang terkait dengan pohon lama akan hilang.

Any components below the root will also get unmounted and have their state destroyed. For example, when diffing:
Komponen manapun di bawah *root* juga akan dilepas dan *state* nya dihancurkan. Sebagai contoh, saat membedakan:

```xml
<div>
Expand All @@ -40,44 +40,43 @@ Any components below the root will also get unmounted and have their state destr
<Counter />
</span>
```
Ini akan menghancurkan `Counter` lama dan memasang kembali yang baru.

This will destroy the old `Counter` and remount a new one.
### Elemen DOM Dari Jenis Yang Sama {#dom-elements-of-the-same-type}

### DOM Elements Of The Same Type {#dom-elements-of-the-same-type}

When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes. For example:
Saat membandingkan dua elemen DOM React dari jenis yang sama, React melihat atribut keduanya, menjaga node DOM dengan dasar yang sama, dan hanya memperbarui atribut yang berubah. Sebagai contoh:

```xml
<div className="before" title="stuff" />

<div className="after" title="stuff" />
```

By comparing these two elements, React knows to only modify the `className` on the underlying DOM node.
Dengan membandingkan dua elemen ini, React tahu untuk hanya memodifikasi `className` pada node DOM yang mendasarinya.

When updating `style`, React also knows to update only the properties that changed. For example:
Saat memperbarui `style`, React juga tahu untuk hanya memperbarui properti yang berubah. Sebagai contoh:

```xml
<div style={{color: 'red', fontWeight: 'bold'}} />

<div style={{color: 'green', fontWeight: 'bold'}} />
```

When converting between these two elements, React knows to only modify the `color` style, not the `fontWeight`.
Saat mengkonversi diantara dua elemen ini, React tahu untuk hanya memodifikasi *style* `color`, bukan `fontWeight`.

After handling the DOM node, React then recurses on the children.
Setelah menangani node DOM, React lalu berulang pada *children*.

### Component Elements Of The Same Type {#component-elements-of-the-same-type}
### Elemen Komponen Dari Jenis Yang Sama {#component-elements-of-the-same-type}

When a component updates, the instance stays the same, so that state is maintained across renders. React updates the props of the underlying component instance to match the new element, and calls `componentWillReceiveProps()` and `componentWillUpdate()` on the underlying instance.
Saat komponen diperbarui, *instance*-nya tetap sama, jadi *state* tersebut terjaga di berbagai *render*. React memperbarui *prop* yang mendasari *instance* komponen untuk mencocokan elemen baru, dan memanggil `componentWillReceiveProps()` dan `componentWillUpdate()` di *instance* yang mendasari.

Next, the `render()` method is called and the diff algorithm recurses on the previous result and the new result.
Selanjutnya, metode `render()` dipanggil dan algoritma pembeda berulang pada hasil sebelumnya dan hasil yang baru.

### Recursing On Children {#recursing-on-children}
### Berulang Di Children {#recursing-on-children}

By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there's a difference.
Secara standar, saat berulang pada *children* node DOM, React hanya melakukan iterasi di atas kedua daftar *children* di waktu bersamaan dan menghasilkan mutasi setiap kali ada perbedaan.

For example, when adding an element at the end of the children, converting between these two trees works well:
Sebagai contoh, saat menambahkan sebuah elemen pada akhir *children*, mengkonversi diantara kedua pohon ini bekerja dengan baik:

```xml
<ul>
Expand All @@ -92,9 +91,9 @@ For example, when adding an element at the end of the children, converting betwe
</ul>
```

React will match the two `<li>first</li>` trees, match the two `<li>second</li>` trees, and then insert the `<li>third</li>` tree.
React akan mencocokan kedua pohon `<li>first</li>`, mencocokan kedua pohon `<li>second</li>`, dan lalu memasukan pohon `<li>third</li>`.

If you implement it naively, inserting an element at the beginning has worse performance. For example, converting between these two trees works poorly:
Jika Anda mengimplementasikan dengan naifnya, memasukan sebuah elemen di awal memiliki kinerja lebih buruk. Sebagai contoh, mengkonversi diantara kedua pohon ini bekerja dengan buruk:

```xml
<ul>
Expand All @@ -109,11 +108,11 @@ If you implement it naively, inserting an element at the beginning has worse per
</ul>
```

React will mutate every child instead of realizing it can keep the `<li>Duke</li>` and `<li>Villanova</li>` subtrees intact. This inefficiency can be a problem.
React akan mengubah setiap *child* daripada menyadari itu dapat menjaga keutuhan sub-pohon `<li>Duke</li>` dan `<li>Villanova</li>`. Ketidakefisienan ini bisa menjadi masalah.

### Keys {#keys}
### Kunci {#keys}
resir014 marked this conversation as resolved.
Show resolved Hide resolved

In order to solve this issue, React supports a `key` attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a `key` to our inefficient example above can make the tree conversion efficient:
Untuk mengatasi masalah ini, React mendukung atribut `key`. Saat *children* memiliki kunci, React menggunakan kunci untuk mencocokan *children* di dalam pohon yang asli dengan *children* di dalam pohon selanjutnya. Sebagai contoh, menambahkan `key` pada contoh tidak efisien kita diatas dapat membuat konversi pohon efisien:
resir014 marked this conversation as resolved.
Show resolved Hide resolved

```xml
<ul>
Expand All @@ -128,30 +127,30 @@ In order to solve this issue, React supports a `key` attribute. When children ha
</ul>
```

Now React knows that the element with key `'2014'` is the new one, and the elements with the keys `'2015'` and `'2016'` have just moved.
Sekarang React tahu bahwa elemen dengan kunci `'2014'` adalah yang baru, dan elemen dengan kunci `'2015'` dan `'2016'` telah dipindahkan.
resir014 marked this conversation as resolved.
Show resolved Hide resolved

In practice, finding a key is usually not hard. The element you are going to display may already have a unique ID, so the key can just come from your data:
Dalam prakteknya, menemukan sebuah kunci biasanya tidak sulit. Elemen yang akan Anda tampilkan mungkin sudah memiliki ID yang unik, jadi kuncinya bisa saja berasal dari data Anda:

```js
<li key={item.id}>{item.name}</li>
```

When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key. The key only has to be unique among its siblings, not globally unique.
Saat itu bukan kasusnya, Anda dapat menambahkan properti ID baru pada model Anda atau *hash* beberapa bagian dari konten untuk menghasilkan sebuah kunci. Kunci hanya harus unik antar *sibling*, bukan unik secara global.

As a last resort, you can pass an item's index in the array as a key. This can work well if the items are never reordered, but reorders will be slow.
Sebagai pilihan terakhir, Anda dapat mengoper sebuah indeks *item* dalam senarai (*array*) sebagai kunci. Ini dapat bekerja dengan baik jika *item-item* tidak pernah diurutkan kembali, tetapi pengurutan kembali akan menjadi lambat.

Reorders can also cause issues with component state when indexes are used as keys. Component instances are updated and reused based on their key. If the key is an index, moving an item changes it. As a result, component state for things like uncontrolled inputs can get mixed up and updated in unexpected ways.
Pengurutan kembali juga dapat menyebabkan masalah dengan *state* komponen saat indeks digunakan sebagai kunci. *Instance* komponen diperbarui dan digunakan kembali berdasarkan kuncinya. Jika kunci adalah indeks, memindahkan sebuah *item* akan mengubahnya. Sebagai hasil, *state* komponen untuk hal seperti *uncontrolled input* dapat tercampur dan diperbarui dengan cara yang tidak terduga.

[Here](codepen://reconciliation/index-used-as-key) is an example of the issues that can be caused by using indexes as keys on CodePen, and [here](codepen://reconciliation/no-index-used-as-key) is an updated version of the same example showing how not using indexes as keys will fix these reordering, sorting, and prepending issues.
[Disini](codepen://reconciliation/index-used-as-key) adalah contoh masalah yang dapat disebabkan oleh penggunaan indeks sebagai kunci pada CodePen, dan [disini](codepen://reconciliation/no-index-used-as-key) adalah versi terbaru dari contoh yang sama menunjukan bagaimana agar tidak menggunakan indeks sebagai kunci akan memperbaiki pengurutan kembali, penyortiran, dan masalah yang saling terkait ini.

## Tradeoffs {#tradeoffs}
## Pengorbanan {#tradeoffs}

It is important to remember that the reconciliation algorithm is an implementation detail. React could rerender the whole app on every action; the end result would be the same. Just to be clear, rerender in this context means calling `render` for all components, it doesn't mean React will unmount and remount them. It will only apply the differences following the rules stated in the previous sections.
Penting untuk diingat bahwa algoritma rekonsiliasi adalah sebuah detail implementasi. React dapat *render* kembali seluruh aplikasi pada setiap aksi; hasil akhirnya akan sama. Untuk lebih jelasnya, *render* kembali di konteks ini berarti memanggil `render` untuk semua komponen, ini bukan berarti React akan melepaskan dan memasangnya kembali. Itu hanya akan menerapkan perbedaan mengikuti aturan yang disebutkan di bagian sebelumnya.

We are regularly refining the heuristics in order to make common use cases faster. In the current implementation, you can express the fact that a subtree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will rerender that full subtree.
Kita secara teratur memperbaiki heuristik untuk membuat contoh kasus umum menjadi lebih cepat. Dalam implementasi saat ini, Anda dapat mengekspresikan fakta bahwa sebuah sub-pohon telah dipindahkan diantara *sibling*, tetapi Anda tidak dapat mengatakan bahwa itu telah dipindahkan ke tempat lain. Algoritma akan *render* ulang sub-pohon itu sepenuhnya.

Because React relies on heuristics, if the assumptions behind them are not met, performance will suffer.
Karena React bergantung pada heuristik, jika asumsi dibelakang mereka tidak terpenuhi, kinerja akan menderita.

1. The algorithm will not try to match subtrees of different component types. If you see yourself alternating between two component types with very similar output, you may want to make it the same type. In practice, we haven't found this to be an issue.
1. Algoritma tidak akan mencoba untuk mencocokan sub-pohon dari jenis komponen yang berbeda. Jika Anda melihat diri Anda sendiri bergantian antara dua jenis komponen dengan keluaran yang sangat mirip, Anda mungkin ingin untuk membuatnya menjadi jenis yang sama. Dalam prakteknya, Kita belum menemukan ini sebagai masalah.

2. Keys should be stable, predictable, and unique. Unstable keys (like those produced by `Math.random()`) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.
2. Kunci harus stabil, dapat diprediksi, dan unik. Kunci yang tidak stabil (seperti yang diproduksi oleh `Math.random()`) akan menyebabkan banyak *instance* komponen dan node DOM tidak perlu diciptakan kembali, yang dapat menyebabkan penurunan kinerja dan *state* hilang dalam komponen *child*.